"The people discussing what programming language is best are not shipping products. The people who don't care what programming language they're using are shipping products." — Pieter Levels
A fully functional job board web app in a single PHP file (index.php),
inspired by Pieter Levels' RemoteOK —
the remote job board that generated over $65,000/month as a single index.php.
- What is this?
- Architecture Overview
- Request Lifecycle
- Prerequisites
- Getting Started
- Project Structure
- Levelsio Principles Applied
- Extension Ideas
- Sources & References — Pieter Levels' Architecture
- Production: NGINX Configuration
- What You Can Learn From This
- Contributing
- Disclaimer
- License
This repo is a learning and reference project. It demonstrates how to build a functional web application with deliberately simple tools — one PHP file, SQLite, jQuery, no framework — that is immediately runnable.
This approach stands in contrast to modern web development with its build pipelines, dependency trees, and layers of abstraction. Levels calls it "Duct Tape Programming": pragmatic, fast, iterative. Not pretty, but profitable.
This repo is not a production template, but an annotated study of this architectural philosophy. Every section of the code is thoroughly documented so you can understand how and why things are structured the way they are.
┌──────────────────────────────────────────────────────────────┐
│ index.php │
│ │
│ ┌──────────────┐ Section 1: Configuration │
│ │ define() │ Constants instead of .env / config class │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ Section 2: Database │
│ │ SQLite + PDO │ Schema auto-created on first run │
│ └──────┬───────┘ No MySQL server required │
│ ▼ │
│ ┌──────────────┐ Section 3: Helper Functions │
│ │ slugify() │ Small utilities: escaping, CSRF, │
│ │ e(), csrf() │ time formatting, redirects │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ Section 4: Controllers / Actions │
│ │ action_home │ Each function = one page │
│ │ action_job │ Contains DB queries + logic │
│ │ action_post │ Calls render_page() at the end │
│ │ action_api │ │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ Section 5: Router │
│ │ router() │ Parses REQUEST_URI │
│ │ if/elseif │ Calls the appropriate action_*() │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ Section 6: Views (HTML/CSS/JS) │
│ │ render_page()│ Everything inline: CSS in <head>, │
│ │ if ($view) │ JS before </body>, HTML mixed with PHP │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ Section 7: Bootstrap │
│ │ router(); │ One line starts the entire app │
│ └───────────┬──┘ │
└──────────────┼───────────────────────────────────────────────┘
▼
(Bootstrap)
Browser → NGINX → index.php → router()
│
┌───────────┼───────────┐
▼ ▼ ▼
action_home action_job action_post
│ │ │
▼ ▼ ▼
db()->query() ... db()->exec()
│ │
└───────┬───────────────┘
▼
render_page($view, $data)
│
▼
HTML + CSS + JS → Browser
- PHP 8.0+ (tested with 8.2)
- No other dependencies — no Composer, no npm, no build step
# Clone the repository
git clone https://github.com/YOUR-USERNAME/levelsio-php-architecture.git
cd levelsio-php-architecture
# Start — that's it
php -S localhost:8000 index.php
# Open your browser
open http://localhost:8000The SQLite database (database.sqlite) is created automatically on the first request.
No setup, no migration script, no seed command.
.
├── index.php ← The entire app (the only file you need)
├── database.sqlite ← Auto-created on first request
├── LICENSE ← MIT License
└── README.md ← This file
Yes, that's everything. That's the point.
| Principle | Implementation |
|---|---|
| Single File | Everything in index.php — routing, logic, views, CSS, JS |
| SQLite | No MySQL setup, the DB is just a file |
| No Framework | Vanilla PHP, no Laravel/Symfony |
| jQuery | Instead of React/Vue — loaded from CDN |
| Inline CSS | No build tools, no Webpack, no PostCSS |
| SFTP Deploy | Upload the file = deployment done |
| Pragmatic | Functional > Elegant. Shipping > Perfection |
- Stripe Payment: Checkout session before publishing a job
- Email Alerts: SQLite table
subscribers+ cron job - RSS Feed: Simply add as another route
/feed - Telegram Bot: Cron job that posts new jobs via Bot API
- Admin Panel: Route
/adminwith password check
The tweet that made the "Single PHP File" philosophy famous:
- "RemoteOK.io is a single PHP file called index.php generating $65,651 this month" https://x.com/levelsio/status/1308145873843560449
-
"How I build my minimum viable products" — Detailed description of his project structure, tech stack (NGINX, Linode, PHP, SQLite) and workflow: https://levels.io/how-i-build-my-minimum-viable-products/
-
"Normalization of non-deviance" — Why he deliberately uses "primitive" tools (SFTP deploy, Sublime Text, no framework), and how he later adopted Git/Composer: https://levels.io/deviance/
-
"How I built Remote OK and launched it to #1 on Product Hunt" — The origin story of RemoteOK, how he scrapes job feeds, normalizes data, and handles URL routing via NGINX: https://levels.io/remote-ok/
- "MAKE: The Indie Maker Blueprint" — Levels' complete philosophy on building profitable startups without funding. Idea → Build → Launch → Grow → Monetize: https://readmake.com/
-
Lex Fridman Podcast #440 — 3-hour conversation about his tech stack, workflow, PHP philosophy, and the creation of his products: https://www.youtube.com/watch?v=oFtjKbXKqbg
-
Indie Hackers Interview — "Growing a Community for Digital Nomads to $33,000/mo", describing the stack ("HTML, CSS, JavaScript and PHP on a Linode VPS running NGINX"): https://www.indiehackers.com/interview/growing-a-community-for-digital-nomads-to-33-000-mo-126df0fc5e
-
"Profitable remote job site built with single PHP file (4.5K lines of code)" — Community debate on the pros and cons of single-file architecture: https://news.ycombinator.com/item?id=16043643
-
Follow-up HN discussion on the $65k/month tweet: https://news.ycombinator.com/item?id=28874671
-
"Digital Nomad to Prolific Indie Hacker — Pieter Levels" — Solid summary of his philosophy, products, and lessons learned: https://thewizdomproject.com/pieter-levels-podcast-notes
-
"Pieter Levels makes $2.9m a year" — Analysis of his career path and unconventional coding approach: https://www.nocsdegree.com/pieter-levels-learn-coding/
| Product | URL | Description |
|---|---|---|
| RemoteOK | https://remoteok.com | The job board (single PHP file origin) |
| Nomad List | https://nomadlist.com | City index for digital nomads |
| Photo AI | https://photoai.com | AI photo generation |
| Interior AI | https://interiorai.com | AI interior design |
| Hoodmaps | https://hoodmaps.com | Crowdsourced neighborhood maps |
- JobBoardSearch.com by Rod (@rrmdp) — Also built in the Levelsio style, "raw PHP in a single index.php file", generated over $40k in revenue: https://www.indiehackers.com/post/made-4k-with-job-board-search-1e57cb88ef
For production use (instead of php -S) you need an NGINX config that routes
all requests to index.php — exactly how Levels does it:
server {
listen 80;
server_name jobboard.example.com;
root /var/www/jobboard;
index index.php;
# Everything that isn't a real file → index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Prevent SQLite DB from being accessible via web
location ~ \.sqlite$ {
deny all;
}
}This project is particularly useful for understanding the following concepts:
- Request routing without a framework — How URLs are mapped to functions
- SQLite as an embedded database — When it's enough and when it's not
- Inline rendering — HTML/CSS/JS in one file, no template engine
- CSRF protection — Manual token implementation without middleware
- Pragmatic validation — Direct checks instead of validation libraries
- SEO-friendly URLs — NGINX rewrite + PHP routing combined
- Monetization patterns — Featured/Standard pricing like RemoteOK
This repo is intended as a learning resource. Contributions are welcome, especially:
- Improve comments — Even clearer explanations in
index.php - Add more Levelsio patterns — e.g. RSS feed, Telegram bot, admin panel
- Fix bugs — If you spot something, feel free to open an issue or PR
- Translations — Additional language versions of the documentation
Please do not introduce frameworks, build tools, or dependency managers — that would defeat the purpose of this project. The constraint of a single file and vanilla PHP is intentional.
This project is not affiliated with Pieter Levels or RemoteOK. It is an independent, annotated recreation of his publicly documented architecture for educational purposes. RemoteOK® is a registered trademark of Pieter Levels.
The code in this repository is a simplified example. For production use it is missing, among other things: rate limiting, input sanitization for XSS in rich-text fields, Stripe integration, email verification, and an admin panel.
MIT License — see LICENSE.
You are free to use, modify, and distribute this code. Attribution is appreciated but not required.