[{"data":1,"prerenderedAt":189},["ShallowReactive",2],{"seo-verification":3,"blog-deploy-a-symfony-application-on-a-vps-ma-en":6,"promo-bar-likely":188},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-deploy-a-symfony-application-on-a-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":129,"ctaBody":130,"ctaButton":131,"ctaUrl":132,"relatedPosts":133},48,"deploy-a-symfony-application-on-a-vps",{"fr":12,"en":10,"ar":13,"es":14},"deployer-symfony-vps","نشر-تطبيق-symfony-على-vps","desplegar-symfony-en-un-vps","Deploy Symfony on VPS: complete guide 2024","Install, configure and secure a Symfony app on Ubuntu VPS with PHP 8.3, Deployer PHP, nginx, Supervisor and Redis. Step-by-step guide.",9,3,false,"2026-05-03T00:00:00+00:00","2026-11-08T01:13:13+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-symfony-vps-poster.svg",{"categorySlug":34,"appSlug":35},"development","symfony-stack","A VPS gives you the full control Symfony deserves: PHP 8.3, native extensions, asynchronous workers and root access. This guide covers PHP 8.3 installation, automated deployment with Deployer PHP, nginx and Supervisor configuration for queues, and security hardening. At the end, discover how the ServOrbit Marketplace automates the entire stack in a few clicks.",[38,42,53,56,84,111,114,117,120,123,126],{"type":39,"title":40,"body":41},"h2","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.4 LTS requires PHP 8.2 as a minimum and Symfony 8 requires PHP 8.4 — versions many shared hosts still don't offer. 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.\n\nAsynchronous 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.",{"type":43,"title":44,"items":45},"ul","What a VPS unlocks for Symfony",[46,47,48,49,50,51,52],"**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, and the `#[Override]` attribute 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\u002Fphp** — 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\u002FCD pipeline",{"type":39,"title":54,"body":55},"Measured prerequisites — resources and software","**Operating system**: Ubuntu 24.04 LTS or Debian 12. Both distributions benefit from Ondřej Surý's PHP repository (the `ondrej\u002Fphp` PPA on Ubuntu, `packages.sury.org` on Debian) and long-term support compatible with Symfony maintenance cycles.\n\n**PHP**: 8.3 recommended for Symfony 7.4 LTS (minimum 8.2). Symfony 8 requires PHP 8.4: replace `8.3` with `8.4` in the package names. 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.\n\n**Composer**: version 2.x required.\n\n**Database**: MySQL 8.0+ or PostgreSQL 16+.\n\n**Minimum RAM**:\n- 1 GB: development or light app without queues\n- 2 GB: production with Symfony Messenger and one Redis transport\n- 4 GB: multiple workers, Redis, high-frequency sessions\n\n**Ports to open**: 80 (HTTP), 443 (HTTPS), 22 (SSH). Close everything else.",{"type":57,"title":58,"steps":59},"steps","Install PHP 8.3 and Symfony CLI on Ubuntu VPS",[60,63,66,69,72,75,78,81],{"title":61,"body":62},"Update the system and install prerequisites","`apt update && apt upgrade -y && apt install -y curl git unzip software-properties-common`",{"title":64,"body":65},"Add the ondrej\u002Fphp repository","`add-apt-repository ppa:ondrej\u002Fphp && apt update`",{"title":67,"body":68},"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`",{"title":70,"body":71},"Verify the installed version and FPM service status","`php --version && systemctl status php8.3-fpm`",{"title":73,"body":74},"Install Composer 2.x globally","`curl -sS https:\u002F\u002Fgetcomposer.org\u002Finstaller | php -- --install-dir=\u002Fusr\u002Flocal\u002Fbin --filename=composer && composer --version`",{"title":76,"body":77},"Install the Symfony CLI","`curl -1sLf 'https:\u002F\u002Fdl.cloudsmith.io\u002Fpublic\u002Fsymfony\u002Fstable\u002Fsetup.deb.sh' | bash && apt install -y symfony-cli`",{"title":79,"body":80},"Check that all Symfony requirements are satisfied","`symfony check:requirements`",{"title":82,"body":83},"Install nginx and Redis","`apt install -y nginx redis-server && systemctl enable --now nginx redis-server`",{"type":57,"title":85,"steps":86},"Deploy a Symfony app to production with Deployer PHP",[87,90,93,96,99,102,105,108],{"title":88,"body":89},"In your local Symfony project, add Deployer as a dev dependency","`composer require deployer\u002Fdeployer --dev`",{"title":91,"body":92},"Initialize the Deployer configuration (choose the `symfony` recipe)","`.\u002Fvendor\u002Fbin\u002Fdep init`",{"title":94,"body":95},"Edit `deploy.php` at the project root — adapt host, deploy path and branches","require 'recipe\u002Fsymfony.php';\nset('repository', 'git@github.com:your-org\u002Fyour-app.git');\nhost('your-vps.example.com')\n    ->set('remote_user', 'deploy')\n    ->set('deploy_path', '\u002Fvar\u002Fwww\u002Fsymfony-app');",{"title":97,"body":98},"On the VPS, create the deployment user","`useradd -m -s \u002Fbin\u002Fbash deploy && usermod -aG www-data deploy`",{"title":100,"body":101},"Create `.env.local` on the VPS in `{{deploy_path}}\u002Fshared\u002F` — shared across all releases","APP_ENV=prod\nAPP_DEBUG=false\nAPP_SECRET=\u003Crandom-32-char-secret>\nDATABASE_URL=mysql:\u002F\u002Fuser:pass@127.0.0.1:3306\u002Fsymfony_db",{"title":103,"body":104},"Run the first deployment from your local machine","`.\u002Fvendor\u002Fbin\u002Fdep deploy your-vps.example.com`",{"title":106,"body":107},"Verify the `current\u002F` symlink points to the latest release","`ls -la \u002Fvar\u002Fwww\u002Fsymfony-app\u002F`",{"title":109,"body":110},"If something goes wrong, roll back immediately","`.\u002Fvendor\u002Fbin\u002Fdep rollback your-vps.example.com`",{"type":39,"title":112,"body":113},"nginx configuration for Symfony","Create `\u002Fetc\u002Fnginx\u002Fsites-available\u002Fsymfony-app` with this minimal server block, then enable it with a symlink to `sites-enabled\u002F`. Only `index.php` is passed to PHP-FPM: a `.php` file dropped anywhere else in `public\u002F` returns 404 instead of being executed.\n\n```nginx\nserver {\n    listen 80;\n    server_name your-domain.com;\n    root \u002Fvar\u002Fwww\u002Fsymfony-app\u002Fcurrent\u002Fpublic;\n    index index.php;\n\n    location \u002F {\n        try_files $uri \u002Findex.php$is_args$args;\n    }\n\n    location ~ ^\u002Findex\\.php(\u002F|$) {\n        fastcgi_pass unix:\u002Frun\u002Fphp\u002Fphp8.3-fpm.sock;\n        fastcgi_split_path_info ^(.+\\.php)(\u002F.*)$;\n        include fastcgi_params;\n        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;\n        fastcgi_param DOCUMENT_ROOT $realpath_root;\n        internal;\n    }\n\n    # any other .php file in public\u002F: 404, never executed\n    location ~ \\.php$ {\n        return 404;\n    }\n\n    location ~ \u002F\\.ht {\n        deny all;\n    }\n}\n```\n\nEnable the site and test before reloading nginx:\n`ln -s \u002Fetc\u002Fnginx\u002Fsites-available\u002Fsymfony-app \u002Fetc\u002Fnginx\u002Fsites-enabled\u002F && nginx -t && systemctl reload nginx`\n\nFor HTTPS, use Certbot: `certbot --nginx -d your-domain.com`.",{"type":39,"title":115,"body":116},"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.\n\nEssential production variables:\n\n```dotenv\nAPP_ENV=prod\nAPP_DEBUG=false\nAPP_SECRET=\u003C64-chars-hex-random>\nDATABASE_URL=\"mysql:\u002F\u002Fdbuser:password@127.0.0.1:3306\u002Fsymfony_prod\"\nMAILER_DSN=smtp:\u002F\u002Fuser:pass@smtp.example.com:587\nMESSENGER_TRANSPORT_DSN=redis:\u002F\u002F127.0.0.1:6379\u002Fmessages\n```\n\nGenerate APP_SECRET randomly: `openssl rand -hex 32`. Never reuse the project's default value.\n\n`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.",{"type":39,"title":118,"body":119},"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.\n\nInstall Supervisor:\n`apt install -y supervisor`\n\nCreate `\u002Fetc\u002Fsupervisor\u002Fconf.d\u002Fsymfony-messenger.conf`:\n\n```ini\n[program:symfony-messenger]\ncommand=\u002Fvar\u002Fwww\u002Fsymfony-app\u002Fcurrent\u002Fbin\u002Fconsole messenger:consume async --time-limit=3600\nuser=deploy\nautostart=true\nautorestart=true\nstartretries=3\nredirect_stderr=true\nstdout_logfile=\u002Fvar\u002Flog\u002Fsupervisor\u002Fsymfony-messenger.log\n```\n\nActivate and start the worker:\n`supervisorctl reread && supervisorctl update && supervisorctl start symfony-messenger`\n\nMonitor status: `supervisorctl status symfony-messenger`",{"type":121,"body":122},"tip","**Hardening in 3 commands.** Block `.git\u002F` access in nginx (add `location ~ \u002F\\.git { deny all; }` to your server block). Install fail2ban to block SSH scans: `apt install -y fail2ban`. Restrict deployment directory permissions: `chmod 750 \u002Fvar\u002Fwww\u002Fsymfony-app && chown -R deploy:www-data \u002Fvar\u002Fwww\u002Fsymfony-app`. Configure OPcache in `\u002Fetc\u002Fphp\u002F8.3\u002Ffpm\u002Fconf.d\u002F10-opcache.ini`: `opcache.enable=1`, `opcache.memory_consumption=256`, `opcache.validate_timestamps=0` in production.",{"type":39,"title":124,"body":125},"Troubleshooting — the 4 most common errors","**1. `The environment variable \"APP_SECRET\" is not set.`**\nAPP_SECRET is missing from `.env.local` on the server. Check that the file exists in `{{deploy_path}}\u002Fshared\u002F` 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`.\n\n**2. Silent 500 error — empty logs**\nWith `APP_DEBUG=false`, Symfony shows nothing in the browser and writes to `var\u002Flog\u002Fprod.log`. Read this file in real time: `tail -f \u002Fvar\u002Fwww\u002Fsymfony-app\u002Fcurrent\u002Fvar\u002Flog\u002Fprod.log`. A permission denied error on `var\u002Fcache\u002F` or `var\u002Flog\u002F` is the most common cause — fix with `chown -R deploy:www-data var\u002F`.\n\n**3. `Connection refused` on the database**\nDATABASE_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`.\n\n**4. `Unable to write in the \"cache\" directory`**\nThis message means Symfony can't write to `var\u002Fcache\u002F`. Fix: `chmod -R 775 var\u002Fcache var\u002Flog && chown -R deploy:www-data var\u002F`.",{"type":39,"title":127,"body":128},"Deploy from the ServOrbit Marketplace","If you prefer to skip hours of manual configuration, the **symfony-stack** template in the ServOrbit Marketplace automatically installs this guide's software stack on Ubuntu 24.04: PHP 8.3-FPM and its extensions, Composer, nginx, PostgreSQL 16, Redis and Supervisor. There is no web interface: you get root SSH access to configure the nginx server block, the Supervisor worker and permissions as described above.\n\nThe template installs PostgreSQL, not MySQL: write a `postgresql:\u002F\u002F…` `DATABASE_URL` in `.env.local`, with an `APP_SECRET` generated by `openssl rand -hex 32`, or install MySQL and `php8.3-mysql` if your application depends on it.\n\nYou 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.","Deploy Symfony on VPS","\u002Fapplications\u002Fdevelopment\u002Fsymfony-stack",[134,152,170],{"id":135,"slug":136,"slugs":137,"title":141,"excerpt":142,"readTime":23,"views":143,"isPinned":19,"noindex":19,"publishedAt":144,"updatedAt":145,"category":146,"categories":147,"featuredImage":30,"bgImage":31,"posterImage":149,"relatedSolution":150},5,"deploying-laravel-on-a-vps-a-production-guide",{"fr":138,"en":136,"ar":139,"es":140},"deployer-laravel-vps","نشر-laravel-على-خادم-vps-دليل-الإنتاج","desplegar-laravel-en-un-vps","Deploying Laravel on a VPS: a production guide","Take Laravel to production on a VPS: PHP, workers, cache, database, reverse proxy and HTTPS configured cleanly.",1,"2026-02-09T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[148],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-laravel-vps-poster.svg",{"categorySlug":27,"appSlug":151},"laravel-stack",{"id":153,"slug":154,"slugs":155,"title":159,"excerpt":160,"readTime":161,"views":143,"isPinned":19,"noindex":19,"publishedAt":162,"updatedAt":163,"category":164,"categories":165,"featuredImage":30,"bgImage":31,"posterImage":167,"relatedSolution":168},43,"deploy-a-nodejs-application-on-a-vps",{"fr":156,"en":154,"ar":157,"es":158},"deployer-nodejs-vps","نشر-تطبيق-nodejs-على-vps","desplegar-una-aplicacion-nodejs-en-un-vps","Deploy a Node.js Application on a VPS","Deploy a Node.js application to production on a VPS: PM2, Nginx reverse proxy, Let's Encrypt SSL, and automatic startup at boot.",8,"2026-05-08T00:00:00+00:00","2026-11-08T01:13:12+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[166],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-nodejs-vps-poster.svg",{"categorySlug":34,"appSlug":169},"nodejs-stack",{"id":171,"slug":172,"slugs":173,"title":177,"excerpt":178,"readTime":18,"views":179,"isPinned":19,"noindex":19,"publishedAt":180,"updatedAt":181,"category":182,"categories":183,"featuredImage":30,"bgImage":31,"posterImage":185,"relatedSolution":186},44,"deploy-a-django-application-on-a-vps",{"fr":174,"en":172,"ar":175,"es":176},"deployer-django-vps","نشر-تطبيق-django-على-vps","desplegar-una-aplicacion-django-en-un-vps","Deploy a Django Application on a VPS","Deploy Django on a VPS: Gunicorn, Nginx, PostgreSQL, Docker, and SSL. A complete guide for Python developers who want to self-host.",7,"2026-05-07T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[184],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fdeployer-django-vps-poster.svg",{"categorySlug":34,"appSlug":187},"django",true,1794270386788]