Alpha ZealPHP is early-stage and under active development. APIs may change between minor versions until v1.0. Feedback and bug reports welcome on GitHub.

Ship It

From localhost to production. Plus: when to use ZealPHP and when not to.

You will learn

  • Run ZealPHP as a background daemon
  • Set up Nginx as a reverse proxy (HTTP + WebSocket + SSE)
  • Write a systemd service unit
  • When ZealPHP is the right tool and when it isn't

The problem

Your app runs on localhost:8080. You close the terminal and it dies. You need it on a real server, running 24/7, behind HTTPS, surviving reboots.

1. Daemon mode

php app.php start -p 8080 -d    # daemonize
php app.php status              # check if running
php app.php stop                # stop
php app.php restart             # cycle

The -d flag puts the server in the background. PID files live at /tmp/zealphp/zealphp_{port}.pid. Logs default to /tmp/zealphp/.

2. Nginx reverse proxy

server {
    listen 80;
    server_name myapp.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # WebSocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        # SSE — disable buffering
        proxy_buffering off;
        proxy_cache off;
    }
}

proxy_buffering off is critical for SSE and streaming — without it, Nginx buffers the entire response before forwarding.

3. systemd service

[Unit]
Description=ZealPHP App
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/php app.php start -p 8080
ExecStop=/usr/bin/php app.php stop -p 8080
Restart=on-failure
RestartSec=5
Environment=OPENAI_API_KEY=sk-...

[Install]
WantedBy=multi-user.target

4. Docker

FROM php:8.3-cli
RUN apt-get update && apt-get install -y libssl-dev libcurl4-openssl-dev \
    && pecl install openswoole && docker-php-ext-enable openswoole \
    && pecl install uopz && docker-php-ext-enable uopz
WORKDIR /app
COPY . .
RUN composer install --no-dev
EXPOSE 8080
CMD ["php", "app.php", "start", "-p", "8080"]

5. Environment variables

OPENAI_API_KEY            # Real AI chat; mock mode without it
ZEALPHP_LEARN_AI_MODEL    # Model name (default: gpt-4.1-mini)
ZEALPHP_LEARN_DB_PATH     # SQLite path (default: storage/learn.db)
ZEALPHP_WORKERS           # HTTP worker count (default: CPU cores)
ZEALPHP_PORT              # Listen port (default: 8080)
ZEALPHP_LOG_DIR           # Log directory (default: /tmp/zealphp)

What you built

Over 12 lessons you created a real application:

  • Session-based auth with SQLite + password_hash
  • CRUD notes app with htmx — no page reloads
  • AI chat assistant that streams tool calls via SSE
  • Cross-tab sync via WebSocket
  • Agent-via-API — Python calls the same endpoints as the frontend
  • Parallel I/O with go() + Channel

All served from one php app.php process. No Redis. No Node sidecar. No queue worker. One process, one language.

When ZealPHP is right

ZealPHP on 4 workers benchmarks at 117,000 req/s with 3ms p90 latency. For SaaS dashboards, content sites, internal tools, AI wrappers — it's more than enough. The bottleneck is almost always the database or external API, not the framework.

htmx covers 95% of interactivity needs with four HTML attributes. The remaining 5% (drag-and-drop, collaborative editing, client-side state) is where React earns its complexity.

The boring architecture

A React + Node + Redis + queue-worker stack has six moving parts. A ZealPHP app has one: php app.php. Fewer moving parts means fewer things to monitor, fewer things to break at 3am, fewer things to explain to the next developer.

The boring architecture is the one that ships and stays shipped.

Key Takeaways

  • php app.php start -d daemonizes; systemd keeps it alive
  • Nginx reverse proxy needs proxy_buffering off for SSE/streaming
  • One process handles HTTP, WebSocket, SSE, sessions, shared memory — no external services
  • ZealPHP is right for most web apps; reach for React only when you need client-side state