Deployment
php-via runs as a long-lived OpenSwoole server process. Unlike traditional PHP-FPM setups, the process stays running — all state lives in memory. This page covers production setup with systemd, Caddy, and process management.
Requirements
- PHP 8.4+
- OpenSwoole extension (
pecl install openswooleor packaged asphp8.4-openswoole) - A reverse proxy (Caddy or nginx) to handle TLS and serve static assets
systemd service
Create a service unit at /etc/systemd/system/myapp.service:
[Unit]
Description=My php-via app
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/php /var/www/myapp/app.php
Restart=on-failure
RestartSec=5s
Environment=APP_ENV=production
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable myapp
systemctl start myapp
systemctl status myapp
Caddy reverse proxy
Caddy handles TLS automatically. The key requirement is disabling response buffering for SSE
(the /_sse endpoint streams indefinitely):
myapp.example.com {
# Serve static assets directly
handle /public/* {
root * /var/www/myapp
file_server
}
# Proxy everything else to OpenSwoole
reverse_proxy localhost:3000 {
# Required for SSE: disable buffering
flush_interval -1
# Optional: pass real IP to app
header_up X-Real-IP {remote_host}
}
}
Production config
Tune php-via for production in your app.php:
$config = (new Config())
->withHost('127.0.0.1') // bind locally, let Caddy handle external
->withPort(3000)
->withLogLevel(getenv('APP_ENV') === 'production' ? 'info' : 'debug')
->withTemplateDir(__DIR__ . '/templates')
->withStaticDir(__DIR__ . '/public')
->withSwooleSettings([
'worker_num' => swoole_cpu_num(),
'max_request' => 0, // long-lived process
'enable_coroutine' => true,
]);
Graceful restart
To deploy new code without dropping connections, reload the service:
systemctl reload myapp
# or:
kill -USR1 $(cat /var/run/myapp.pid)
php-via listens for SIGTERM and SIGINT and calls your onShutdown
callbacks before stopping. Register cleanup callbacks for any timers or open resources.
Multiple instances
php-via uses OpenSwoole's in-memory shared state for the scope system. This means multiple instances do not share state — a broadcast on instance A won't reach clients on instance B. For now, horizontal scaling requires a sticky-session load balancer and the understanding that per-route state won't be globally consistent.
Static assets
Configure a static directory to serve files directly from OpenSwoole in development:
$config->withStaticDir(__DIR__ . '/public');
In production, serve static files from Caddy (or nginx) directly — it's faster and avoids passing binary content through PHP.
Next steps
- Lifecycle — onStart, onShutdown, cleanup hooks
- API Reference — Config class options