title: Symfony2 deployment to production using Capistrano 3
body: <p>After getting my head around some local Symfony2 development I wanted to explore how to deploy to live environment and I decided to try Capistrano 3 and the Symfony plugin <a href="https://github.com/capistrano/symfony/" rel="nofollow">https://github.com/capistrano/symfony/</a>.</p>
  
  <p>I've followed a number of guides and read many SO questions/answers and I am able to get my files onto the live server. </p>
  
  <p>I am using Dreamhost on a shared plan and have a web directory of home/myusername/mydomain/web.  After the Capistrano deploy the directory at home/myusername/mydomain looks like this:</p>
  
  <p>current/</p>
  
  <p>releases/</p>
  
  <p>repo/</p>
  
  <p>shared/</p>
  
  <p>tmp/</p>
  
  <p>web/ &lt;--this is not the Symfony web directory but default created by Dreamhost.</p>
  
  <p>However when I visit the site none of my routes work I just get 404s.  If i change the document root from /home/myusername/pickingorganic/web to to /home/myusername/pickingorganic/  then I can access my routes for example mydomain/current/web/login, but obviously I don’t want current/web to appear in the URL.</p>
  
  <p>If I run </p>
  
  <pre><code>ls -la mydomain | grep "\-&gt;" 
  </code></pre>
  
  <p>on the server I can see that the Capistano symlink from current directory seems to be in place correctly </p>
  
  <pre><code>current -&gt; /home/myusername/mydomain/releases/20160112132605
  </code></pre>
  
  <p>I assume that my errors are somewhere in the Symfony web/.htaccess file (which is unmodified) or in my Capistrano settings.  I’ve put these below.  Any advice on where I am going wrong greatly appreciated.  Also if anyone has experience with the Capistrano Symphony plugin especially how to configure the settings shown here <a href="https://github.com/capistrano/symfony/#settings" rel="nofollow">https://github.com/capistrano/symfony/#settings</a> correctly that would be fantastic; I’ve searched for examples or tutorials but not really come across anything.</p>
  
  <p><strong>deploy.rb</strong></p>
  
  <pre><code># config valid only for current version of Capistrano
  lock '3.4.0'
  
  #set :tmp_dir, "#{fetch(:home)}/tmp"
  set :tmp_dir, "/home/myusername/mydomain/tmp"
  
  set :application, 'storyproject'
  set :repo_url, 'git@github.com:githubid/githubproject-project.git'
  
  # Default branch is :master
  # ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
  
  # Default deploy_to directory is /var/www/my_app_name
  set :deploy_to, '/home/myusername/mydomain'
  
  # Default value for :scm is :git
  set :scm, :git
  
  # Default value for :format is :pretty
  # set :format, :pretty
  
  # Default value for :log_level is :debug
  # set :log_level, :debug
  
  # Default value for :pty is false
  # set :pty, true
  
  # Default value for :linked_files is []
  set :linked_files, fetch(:linked_files,
  []).push('app/config/parameters.yml')
  
  # Default value for linked_dirs is []
  set :linked_dirs, fetch(:linked_dirs, []).push('vendor/bundle')
  
  # Default value for default_env is {}
  # set :default_env, { path: "/opt/ruby/bin:$PATH" }
  
  # Default value for keep_releases is 5
  # set :keep_releases, 5
  
  
  #namespace :deploy do
  
  # after :restart, :clear_cache do
  #  on roles(:web), in: :groups, limit: 3, wait: 10 do
    # Here we can do anything such as:
    # within release_path do
    #   execute :rake, 'cache:clear'
    # end
  # end
  #end
  
  #end
  
  namespace :deploy do
  
  desc 'composer install'
  task :composer_install do
      on roles(:web) do
          within release_path do
              execute 'composer', 'install', '--no-dev', '--optimize-   autoloader'
          end
      end
  end
  
  after :updated, 'deploy:composer_install'
  
  desc 'Restart application - does nothing, see comments below'
  task :restart do
      on roles(:app), in: :sequence, wait: 5 do
          # This is present b/c 'cap production deploy' is blowing up w/o it.
          # Not sure what's up with that, the Google hasn't helped, and I'm tired
          # of screwing with it.  It stays in for now.
      end
  end
  
  end
  </code></pre>
  
  <p><strong>production.rb</strong></p>
  
  <pre><code>set :stage, :production
  
  role :web, %w{sshuser@mydomain}
  role :app, %w{sshuser@mydomain}
  
  set :ssh_options, {
  forward_agent: true
  }
  
  
  # Symfony environment
  set :symfony_env,  "prod"
  
  # Symfony application path
  set :app_path,              "app"
  
  # Symfony web path
  set :web_path,              "web"
  
  # Symfony log path
  set :log_path,              fetch(:app_path) + "/logs"
  
  # Symfony cache path
  set :cache_path,            fetch(:app_path) + "/cache"
  
  # Symfony config file path
  set :app_config_path,       fetch(:app_path) + "/config"
  
  # Controllers to clear
  set :controllers_to_clear, ["app_*.php"]
  
  # Files that need to remain the same between deploys
  #set :linked_files,          []
  
  # Dirs that need to remain the same between deploys (shared dirs)
  set :linked_dirs,           [fetch(:log_path), fetch(:web_path) +     "/uploads"]
  
  # Dirs that need to be writable by the HTTP Server (i.e. cache, log dirs)
  set :file_permissions_paths,         [fetch(:log_path), fetch(:cache_path)]
  
  # Name used by the Web Server (i.e. www-data for Apache)
  set :file_permissions_users, ['www-data']
  
  # Name used by the Web Server (i.e. www-data for Apache)
  set :webserver_user,        "www-data"
  
  # Method used to set permissions (:chmod, :acl, or :chgrp)
  set :permission_method,     false
  
  # Execute set permissions
  set :use_set_permissions,   false
  
  # Symfony console path
  set :symfony_console_path, fetch(:app_path) + "/console"
  
  # Symfony console flags
  set :symfony_console_flags, "--no-debug"
  
  # Assets install path
  set :assets_install_path,   fetch(:web_path)
  
  # Assets install flags
  set :assets_install_flags,  '--symlink'
  
  # Assetic dump flags
  set :assetic_dump_flags,  ''
  
  fetch(:default_env).merge!(symfony_env: fetch(:symfony_env))
  
  # server-based syntax
  # ======================
  # Defines a single server with a list of roles and multiple properties.
  # You can define all roles on a single server, or split them:
  
  # server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
  # server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value
  # server 'db.example.com', user: 'deploy', roles: %w{db}
  
  # role-based syntax
  # ==================
  
  # Defines a role with one or multiple servers. The primary server in each
  # group is considered to be the first unless any  hosts have the primary
  # property set. Specify the username and a domain or IP for the server.
  # Don't use `:all`, it's a meta role.
  
  # role :app, %w{deploy@example.com}, my_property: :my_value
  # role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
  # role :db,  %w{deploy@example.com}
  
  # Configuration
  # =============
  # You can set any configuration variable like in config/deploy.rb
  # These variables are then only loaded and set in this stage.
  # For available Capistrano configuration variables see the documentation page.
  # http://capistranorb.com/documentation/getting-started/configuration/
  # Feel free to add new variables to customise your setup.
  
  
  # Custom SSH Options
  # ==================
  # You may pass any option but keep in mind that net/ssh understands a
  # limited set of options, consult the Net::SSH documentation.
  # http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
  #
  # Global options
  # --------------
  #  set :ssh_options, {
  #    keys: %w(/home/rlisowski/.ssh/id_rsa),
  #    forward_agent: false,
  #    auth_methods: %w(password)
  #  }
  #
  # The server-based syntax can be used to override options:
  # ------------------------------------
  # server 'example.com',
  #   user: 'user_name',
  #   roles: %w{web app},
  #   ssh_options: {
  #     user: 'user_name', # overrides user setting above
  #     keys: %w(/home/user_name/.ssh/id_rsa),
  #     forward_agent: false,
  #     auth_methods: %w(publickey password)
  #     # password: 'please use keys'
  #   }
  </code></pre>
  
  <p><strong>Symfony web/.htaccess</strong></p>
  
  <pre><code># Use the front controller as index file. It serves as a fallback solution when
  # every other rewrite/redirect fails (e.g. in an aliased environment without
  # mod_rewrite). Additionally, this reduces the matching process for the
  # start page (path "/") because otherwise Apache will apply the rewriting rules
  # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
  DirectoryIndex app.php
  
  # By default, Apache does not evaluate symbolic links if you did not enable this
  # feature in your server configuration. Uncomment the following line if you
  # install assets as symlinks or if you experience problems related to symlinks
  # when compiling LESS/Sass/CoffeScript assets.
  # Options FollowSymlinks
  
  # Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve
  # to the front controller "/app.php" but be rewritten to "/app.php/app".
  &lt;IfModule mod_negotiation.c&gt;
      Options -MultiViews
  &lt;/IfModule&gt;
  
  &lt;IfModule mod_rewrite.c&gt;
      RewriteEngine On
  
  # Determine the RewriteBase automatically and set it as environment variable.
  # If you are using Apache aliases to do mass virtual hosting or installed the
  # project in a subdirectory, the base path will be prepended to allow proper
  # resolution of the app.php file and to redirect to the correct URI. It will
  # work in environments without path prefix as well, providing a safe, one-size
  # fits all solution. But as you do not need it in this case, you can comment
  # the following 2 lines to eliminate the overhead.
  RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
  RewriteRule ^(.*) - [E=BASE:%1]
  
  # Sets the HTTP_AUTHORIZATION header removed by apache
  RewriteCond %{HTTP:Authorization} .
  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  
  # Redirect to URI without front controller to prevent duplicate content
  # (with and without `/app.php`). Only do this redirect on the initial
  # rewrite by Apache and not on subsequent cycles. Otherwise we would get an
  # endless redirect loop (request -&gt; rewrite to front controller -&gt;
  # redirect -&gt; request -&gt; ...).
  # So in case you get a "too many redirects" error or you always get redirected
  # to the start page because your Apache does not expose the REDIRECT_STATUS
  # environment variable, you have 2 choices:
  # - disable this feature by commenting the following 2 lines or
  # - use Apache &gt;= 2.3.9 and replace all L flags by END flags and remove the
  #   following RewriteCond (best solution)
  RewriteCond %{ENV:REDIRECT_STATUS} ^$
  RewriteRule ^app\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L]
  
  # If the requested filename exists, simply serve it.
  # We only want to let Apache serve files and not directories.
  RewriteCond %{REQUEST_FILENAME} -f
  RewriteRule .? - [L]
  
  # Rewrite all other queries to the front controller.
  RewriteRule .? %{ENV:BASE}/app.php [L]
  &lt;/IfModule&gt;
  
  &lt;IfModule !mod_rewrite.c&gt;
      &lt;IfModule mod_alias.c&gt;
      # When mod_rewrite is not available, we instruct a temporary redirect of
      # the start page to the front controller explicitly so that the website
      # and the generated links can still be used.
      RedirectMatch 302 ^/$ /app.php/
      # RedirectTemp cannot be used instead
    &lt;/IfModule&gt;
  &lt;/IfModule&gt;
  </code></pre>