Krzych Jończyk

Modern PHP, soft skills, productivity and time management.

[Edit] How to deploy Symfony app with Capistrano 3 on cheap OVH VPS

How to deploy Symfony app with Capistrano 3 on cheap OVH VPS


If you want to deploy Symfony app using Capistrano 3 to cheap OVH VPS then you’ll need to write a simple task to set proper permissions.

I have a very cheap VPS in OVH, it costs only about $2 per month. It is perfect for my needs, I have my blog there, I have my friend’s blog as well. And now I want to move my wife’s portfolio from (even cheaper :P) shared hosting to this VPS.

Until now deploy to shared hosting looked like this:

  1. open FTP
  2. go to portfolio directory
  3. move changed files
  4. app/console cache:clear


Fortunately, I had access to SSH on my hosting (not popular thing) so I could try to automate this process a little bit. But because I already have VPS then the better idea was to move the portfolio there and use some tool for deployment.

The portfolio is written using Symfony 2 framework so the best idea is to use Capistrano. I had some experience with Capifony which is pretty old, unmaintained customization for Capistrano 2 (which is also quite old). I don’t want to use old stuff. So the goal is easy: deploy Symfony 2 app using Capistrano 3 to OVH, cheap VPS.


First of all, you’ll need to install Capistrano on your local machine. I used official instruction, a good start will be Quick Start. Then you’ll need to add Symfony tasks to Capistrano (you can write tasks yourself, but it’ll be reinventing the wheel):

And at last, you have to configure it. I used a pretty good description from this post. In case it’ll disappear here are my configs:

Having this I tried to deploy my application using cap production deploy command. The deploy went successfully, but I get HTTP ERROR 500 when I went to project URL…

Main oponent

One of the problems, maybe the biggest, is changing permissions to /logs and /cache directories. Deploy is performed using one user, but the HTTP server works using a different one, often named www-data. So after deploying all permissions are granted for deploying user and, because /cache directory is not writable for www-data, the website is simply not working (you can see the error in /logs/prod.log file, in the web browser you’ll see only HTTP ERROR 500).

There are 3 most used methods to change permissions:

  1. ACL
  2. CHOWN
  3. CHMOD

ACL simply allows you to specify different permissions for many users, so changing them using chown is not needed. Unfortunately, it’s not available on the cheapest OVH VPS 🙁 (I think it is available on the cheapest VPS in DigitalOcean, but it’s $5 😜)

So, I tried chown – that means changing the owner of /cache directory to www-data. It worked, the website was online, but during next deploy, when old releases are deleted there was permission denied error while deleting /cache directory. Which is obviously correct, deploying user is not an owner of it.

Custom task to the rescue!

So, at last, I tried chmod – setting permissions to 777 allows anyone to write to /cache and /logs directory and changing ownership is not needed. Perfect, isn’t it?

No 😜

chmod needs root permissions to be executed. I tried built-in methods in Capistrano to use chmod after deploy, but I failed to make it works. Fortunately, you can write your own tasks, so did I.

The concept is easy: after deploying change permissions to 777 using sudo and a previously typed password. There is a way to make it works without a password, but granting permissions to call chmod without password looks a little dangerous. And typing password during deploy seemed to me like a good compromise.

My task looks like this:

The main part is just a 3 lines:

  1. asking for a password with ask command
  2. executing chmod on /cache directory
  3. executing chmod on /logs directory

The interesting part is setting up permissions. I used sudo with -S option which allowed me to use previously typed password without user interaction. Using just sudo will not work, deploy will simply stick on this. So, with -S option it uses a password from the standard input, in this example from echoing it. And to use password typed in ask command I used #{fetch(:password)}:

  • :password is just a variable name in which the password is stored
  • fetch() fetches a value from the variable
  • #{} displays the value

To use this task you should tell Capistrano to call it after deploy: after :deploy, "deploy:cache_logs_chmod".

The whole deploy.rb file looks like this:


And that’s it. Deploy works, the website works and the only drawback is typing password during deployment. Not a high price for using a very good tool on the very cheap VPS 😉

I couldn’t find a way to do it in a different way so I made it myself and I hope it’ll be useful for you. If I’m wrong and my way to deal with permissions is wrong – let me know, I’ll be very happy to make it works better 🙂

After some deploys…

Unfortunately, this isn’t working properly 🙁 Using different users for deployment and web server without ACL is hard. One user creates directories, warmups cache and so on, and the other makes additional files, caches and so on.

Setting chmod 777 to /cache and /logs directories allows www-data user to write and read from them, but any file created by it has new permissions which prevent deleting directory during rotating releases in deploy.

To better visualization let’s say, that I have user deploy for deployment and www for a web server.

  1. deploy creates /cache directory and set permissions to 777, but he is still its owner
  2. www after some requests creates new files in /cache which have different permissions AND their owner is www user
  3. during deployment deploy user tries to remove old releases and it couldn’t, because some files are not his and deploy stops.

Temporary solution

For now, I make deploy semi-automatically. Before deploying I simply delete old release from server (it needs sudo) and because there are fewer releases than the limit in deploy.rb deployments work fine.

Final solution

I want to try it on DigitalOcean which hasn’t problems with ACL management. I’ll do it in a couple of months when my OVH VPS expire 😉

Want more tech meat?


  1. You could have used Envoyer deploy the symfony app much quicker. Envoyer is a Laravel product, but it can be used with any PHP app. Apart from quick deployment, there is also benefit of zero downtime deployment. This means if you use Envoyer with push a branch from git, the new changes will be updated on your website without any downtime. Source:

  2. What about symfony 4 😉 ?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2020 Krzych Jończyk

Theme by Anders NorenUp ↑