Contents· Why run Symfony on a VPS instead of shared hosting?1/10
  1. 01Why run Symfony on a VPS instead of shared hosting?
  2. 02What a VPS unlocks for Symfony
  3. 03Measured prerequisites — resources and software
  4. 04Install PHP 8.3 and Symfony CLI on Ubuntu VPS
  5. 05Deploy a Symfony app to production with Deployer PHP
  6. 06nginx configuration for Symfony
  7. 07Environment variables and security
  8. 08Async queues with Symfony Messenger and Supervisor
  9. 09Troubleshooting — the 4 most common errors
  10. 10Deploy from the ServOrbit Marketplace

Why run Symfony on a VPS instead of shared hosting?

Shared hosting locks you into the server's PHP version, disables extensions deemed 'unsafe', and forbids persistent background processes. Symfony 7 requires PHP 8.2 as a minimum — a constraint many shared hosts still don't meet. On a VPS, you choose PHP 8.3 from day one, configure OPcache precisely, and install ext-redis, ext-intl or ext-amqp as needed.

Asynchronous workers (Symfony Messenger) require a persistent background process managed by Supervisor or systemd. On shared hosting, this is simply impossible. On a VPS, it starts with one command and restarts automatically after a crash — essential for any Symfony app handling transactional emails, push notifications or file imports.

What a VPS unlocks for Symfony

  • Full root access — install any PHP extension, configure OPcache line by line, and modify php.ini without opening a support ticket
  • Native PHP 8.3 — benefit from typed class constants, the #[Override] attribute and improved JIT performance without waiting for a shared server migration
  • Supervisor and persistent workers — run messenger:consume continuously with automatic restart and log rotation to process your queues without hacky cron jobs
  • Local Redis — install Redis on the same VPS for sessions, Doctrine cache and Messenger transports, eliminating network latency to an external service
  • Multi-version PHP via ondrej/php — maintain PHP 8.1 for a legacy app and PHP 8.3 for a new one on the same host with separate FPM pools
  • Xdebug and profiling in staging — enable Blackfire or Xdebug on the review environment without impacting production, in the same datacenter
  • Atomic deployments with Deployer — zero downtime via symlinks, one-command rollback, dep deploy hooks integrated into your CI/CD pipeline

Measured prerequisites — resources and software

Operating system: Ubuntu 24.04 LTS or Debian 12. Both distributions benefit from the ondrej/php repository and long-term support compatible with Symfony maintenance cycles.

PHP: 8.3 recommended (minimum 8.2 for Symfony 7). Required extensions: php8.3-cli, php8.3-fpm, php8.3-mbstring, php8.3-xml, php8.3-curl, php8.3-zip, php8.3-intl, php8.3-opcache. Add php8.3-redis for Redis, php8.3-pgsql for PostgreSQL.

Composer: version 2.x required.

Database: MySQL 8.0+ or PostgreSQL 16+.

Minimum RAM:
- 1 GB: development or light app without queues
- 2 GB: production with Symfony Messenger and one Redis transport
- 4 GB: multiple workers, Redis, high-frequency sessions

Ports to open: 80 (HTTP), 443 (HTTPS), 22 (SSH). Close everything else.

Install PHP 8.3 and Symfony CLI on Ubuntu VPS

  1. Update the system and install prerequisites

    apt update && apt upgrade -y && apt install -y curl git unzip software-properties-common

  2. Add the ondrej/php repository

    add-apt-repository ppa:ondrej/php && apt update

  3. Install PHP 8.3-FPM and Symfony-required extensions

    apt install -y php8.3-fpm php8.3-cli php8.3-mbstring php8.3-xml php8.3-curl php8.3-zip php8.3-intl php8.3-opcache php8.3-redis php8.3-mysql

  4. Verify the installed version and FPM service status

    php --version && systemctl status php8.3-fpm

  5. Install Composer 2.x globally

    curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && composer --version

  6. Install the Symfony CLI

    curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.deb.sh' | bash && apt install -y symfony-cli

  7. Check that all Symfony requirements are satisfied

    symfony check:requirements

  8. Install nginx and Redis

    apt install -y nginx redis-server && systemctl enable --now nginx redis-server

Deploy a Symfony app to production with Deployer PHP

  1. In your local Symfony project, add Deployer as a dev dependency

    composer require deployer/deployer --dev

  2. Initialize the Deployer configuration (choose the `symfony` recipe)

    ./vendor/bin/dep init

  3. Edit `deploy.php` at the project root — adapt host, deploy path and branches

    require 'recipe/symfony.php';
    set('repository', '[email protected]:your-org/your-app.git');
    host('your-vps.example.com')
    ->set('remote_user', 'deploy')
    ->set('deploy_path', '/var/www/symfony-app');

  4. On the VPS, create the deployment user

    useradd -m -s /bin/bash deploy && usermod -aG www-data deploy

  5. Create `.env.local` on the VPS in `{{deploy_path}}/shared/` — shared across all releases

    APP_ENV=prod
    APP_DEBUG=false
    APP_SECRET=<random-32-char-secret>
    DATABASE_URL=mysql://user:[email protected]:3306/symfony_db

  6. Run the first deployment from your local machine

    ./vendor/bin/dep deploy production

  7. Verify the `current/` symlink points to the latest release

    ls -la /var/www/symfony-app/

  8. If something goes wrong, roll back immediately

    ./vendor/bin/dep rollback production

nginx configuration for Symfony

Create /etc/nginx/sites-available/symfony-app with this minimal server block, then enable it with a symlink to sites-enabled/.

server {
    listen 80;
    server_name your-domain.com;
    root /var/www/symfony-app/current/public;
    index index.php;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
    }

    location ~ /\.ht {
        deny all;
    }
}

Enable the site and test before reloading nginx:
ln -s /etc/nginx/sites-available/symfony-app /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx

For HTTPS, use Certbot: certbot --nginx -d your-domain.com.

Environment variables and security

Symfony reads .env, then .env.local, then .env.prod.local. In production, all sensitive values must be in .env.local — never committed to git.

Essential production variables:

APP_ENV=prod
APP_DEBUG=false
APP_SECRET=<64-chars-hex-random>
DATABASE_URL="mysql://dbuser:[email protected]:3306/symfony_prod"
MAILER_DSN=smtp://user:[email protected]:587
MESSENGER_TRANSPORT_DSN=redis://127.0.0.1:6379/messages

Generate APP_SECRET randomly: openssl rand -hex 32. Never reuse the project's default value.

APP_DEBUG=false is critical: in debug mode, Symfony exposes full stack traces, template variables and SQL queries in the browser — a severe information leak in production.

Async queues with Symfony Messenger and Supervisor

Symfony Messenger defers heavy tasks (email sending, PDF generation, webhooks) to a queue processed asynchronously. On a VPS, Supervisor ensures the worker runs continuously and restarts after a crash.

Install Supervisor:
apt install -y supervisor

Create /etc/supervisor/conf.d/symfony-messenger.conf:

[program:symfony-messenger]
command=/var/www/symfony-app/current/bin/console messenger:consume async --time-limit=3600
user=deploy
autostart=true
autorestart=true
startretries=3
redirect_stderr=true
stdout_logfile=/var/log/supervisor/symfony-messenger.log

Activate and start the worker:
supervisorctl reread && supervisorctl update && supervisorctl start symfony-messenger

Monitor status: supervisorctl status symfony-messenger

Hardening in 3 commands. Block .git/ access in nginx (add location ~ /\.git { deny all; } to your server block). Install fail2ban to block SSH scans: apt install -y fail2ban. Restrict deployment directory permissions: chmod 750 /var/www/symfony-app && chown -R deploy:www-data /var/www/symfony-app. Configure OPcache in /etc/php/8.3/fpm/conf.d/10-opcache.ini: opcache.enable=1, opcache.memory_consumption=256, opcache.validate_timestamps=0 in production.

Troubleshooting — the 4 most common errors

1. The environment variable "APP_SECRET" is not set.
APP_SECRET is missing from .env.local on the server. Check that the file exists in {{deploy_path}}/shared/ and contains this variable. Deployer creates a symlink to this shared file for each release — if the symlink is broken, Symfony won't read .env.local.

2. Silent 500 error — empty logs
With APP_DEBUG=false, Symfony shows nothing in the browser and writes to var/log/prod.log. Read this file in real time: tail -f /var/www/symfony-app/current/var/log/prod.log. A permission denied error on var/cache/ or var/log/ is the most common cause — fix with chown -R deploy:www-data var/.

3. Connection refused on the database
DATABASE_URL points to 127.0.0.1 but MySQL listens on localhost (Unix socket) — or vice versa. Test directly: mysql -u dbuser -p -h 127.0.0.1 symfony_db.

4. There are no commands defined in the "cache" namespace
This misleading message often means Symfony can't write to var/cache/. Fix: chmod -R 775 var/cache var/log && chown -R deploy:www-data var/.

Deploy from the ServOrbit Marketplace

If you prefer to skip hours of manual configuration, the symfony-stack template in the ServOrbit Marketplace automatically installs and configures the entire stack described in this guide: PHP 8.3-FPM, Composer, Symfony-optimized nginx, Redis, Supervisor and correct permissions. The VPS is ready in under 5 minutes, with immediate root SSH access to customize your deployment.

The template also configures essential environment variables through a guided form at order time — randomly generated APP_SECRET, DATABASE_URL pre-filled with MySQL credentials created for your instance.

You keep full control: the VPS is yours, there's no lock-in, and you can use Deployer PHP exactly as described above from your first SSH connection.

Symfony running in 5 minutes

Order a pre-configured VPS with PHP 8.3, nginx, Redis and Supervisor — the complete Symfony stack installed and secured, no manual configuration required.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab