3

When I cap deploy my Symfony2 project, then log into my server I see that the the dev (app_dev.php) runs ok but the prod version (app.php) does not.

The error is

[Tue Jan 03 14:31:48 2012] [error] [client xxx.xxx.xxx.xxx] PHP Fatal error:  Uncaught exception 'RuntimeException' with message 'Failed to write cache file "/var/www/example/prod/releases/20120103202539/app/cache/prod/classes.php".' in /var/www/example/prod/releases/20120103202539/app/bootstrap.php.cache:1079\nStack trace:\n#0 /var/www/example/prod/releases/20120103202539/app/bootstrap.php.cache(1017): Symfony\\Component\\ClassLoader\\ClassCollectionLoader::writeCacheFile('/var/www/example/p...', '<?php  ????name...')\n#1 /var/www/example/prod/releases/20120103202539/app/bootstrap.php.cache(682): Symfony\\Component\\ClassLoader\\ClassCollectionLoader::load(Array, '/var/www/example/p...', 'classes', false, false, '.php')\n#2 /var/www/example/prod/releases/20120103202539/web/app.php(10): Symfony\\Component\\HttpKernel\\Kernel->loadClassCache()\n#3 {main}\n  thrown in /var/www/example/prod/releases/20120103202539/app/bootstrap.php.cache on line 1079

Looking at the recently deployed cache directory I see:

drwxrwxrwx 4 root     root     4096 Jan  3 14:28 .
drwxrwxr-x 5 root     root     4096 Jan  3 14:28 ..
drwxr-xr-x 6 www-data www-data 4096 Jan  3 14:28 dev
drwxrwxr-x 7 root     root     4096 Jan  3 14:28 prod

I can fix the issue with chown -R www-data.www-data prod/ but I wondered if I can stop this from happening in the first place? And why do the directories have different owners?

j0k
  • 22,600
  • 28
  • 79
  • 90
ed209
  • 11,075
  • 19
  • 66
  • 82

4 Answers4

10

This happens because your web-server is running by user, who is not able to write to just created cache/prod directory.

There are two solutions, which I know and use. First, add extra commands to run after deployment to Capfile. Capfile will like this:

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
Dir['vendor/bundles/*/*/recipes/*.rb'].each { |bundle| load(bundle) }
load Gem.find_files('symfony2.rb').last.to_s

after "deploy:finalize_update" do
  run "sudo chown -R www-data:www-data #{latest_release}/#{cache_path}"
  run "sudo chown -R www-data:www-data #{latest_release}/#{log_path}"
  run "sudo chmod -R 777 #{latest_release}/#{cache_path}"
end

load 'app/config/deploy'

Second solution is more elegant. You specify correct user, who can write to cache in deploy.rb and make sure that you don't use sudo:

set :user, "anton"
set :use_sudo, false
Anton Babenko
  • 6,586
  • 2
  • 36
  • 44
  • thanks, sounds like what I need. What I don't understand is why the dev dir is owned by www-data. Capifony runs as user root on the server, so I guess php is trying to create the cache files (rather than the root user) ? – ed209 Jan 05 '12 at 18:47
  • 1
    `cache/dev` dir is created by php running CLI version, which is a different user than the one running web-server. `cache/prod` is running as it would be run by web-server. This is how I understand it :) – Anton Babenko Jan 05 '12 at 19:25
  • I see what you mean, although looking at the dir owners I would say it was the other way around in that /prod is owned by root and /dev is owned by www-data ? – ed209 Jan 06 '12 at 14:49
7

In the last version of capifony, they've added the option to set writable directories. Here's the official article which explains what I've written below : http://capifony.org/cookbook/set-permissions.html

You have to deploy using sudo (not a good practice, but it gets the job done)

set   :use_sudo,      false
# To prompt the sudo password
default_run_options[:pty] = true

and tell capifony which files to make cache and logs folder writable :

set :writable_dirs,     ["app/cache", "app/logs"]
set :webserver_user,    "www-data"
set :permission_method, :acl

(you have to install acl on your machine, or use :chwon instead of :acl)

EDIT : I've just realized that this is not enough, the "set_permissions" task is not automatically called, so you have to explicitly run

cap deploy:set_permissions

Or add this line in your deploy.rb :

before "deploy:restart", "deploy:set_permissions"
Julien
  • 9,312
  • 10
  • 63
  • 86
  • You can also add set `:use_set_permissions, true`in your deploy.rb instead of `before "deploy:restart", "deploy:set_permissions"` – Pierre Dec 10 '14 at 19:17
5

I solved this problem by adding cache folder to shared folders.

set :shared_children,     [app_path + "/cache", app_path + "/logs", web_path + "/uploads", "vendor"]

This way the directory is not recreated each time during deployment, so there is no problem with permissions.

Dziamid
  • 11,225
  • 12
  • 69
  • 104
  • 1
    You might have problem when rolling back. Make sure you clear the cache when role back, too. Ooh, when you try to clear the cache, you bump into the same problem again, you don't have the permission to delete files created by the server. – David Lin Oct 31 '13 at 01:27
1

Yes, don't need recreate cache every time after deploy, this solution is logical and pragmatical.

Second solution from Anton - is work if you cache folder permission true in develop environment