SF2: Apache2 based HTTP-Authentication with Capifony

Almost every RoR dev knows Capistrano. It’s an awesome tool for deploying RoR applications (not only, but let’s leave it at that for know 😉 ) and also as a Symfony2 dev one can harness its power with Capifony.

I usually create Apache2 based HTTP-Authentication by hand for projects where the customer doesn’t provide a dedicated staging server but wants me to deploy on their live-system without going public. But in one of my current projects htpasswd wasn’t available in the restricted SSH-Shell, I could only use their web-based “Directory Security Tool”. That was fine for the first deploy, but afterwards I was always greeted with a 500 server error. But why?

Capifony creates a directory structure for different deployed versions of your application and points via a current named symlink (usually)  to the latest version (example taken from Capifony.org):

`-- /var/www/my-app.com
  |-- current → /var/www/my-app.com/releases/20100512131539
  |-- releases
    |-- 20100512131539
    |-- 20100509150741
    `-- 20100509145325
  `-- shared
    |-- log
    |-- config
      `-- databases.yml
    `-- web
      `-- uploads

SF2 documentation recommends to point the vhost to the /web folder of your application (see SF2 Documentation):

Last but not least, on the production servers, you should point your web root directory to the web/ directory to secure your installation and have an even better looking URL:


The “Directory Security Tool” updated my (shared) .htaccess with default Apache2 authentication directives but saved the .htpasswd file with the login credentials IN the applications /web folder. Now on the next deploy the current symlink was changed to the new version, .htaccess stayed the same (as it was shared), but .htpasswd was gone (at least for apache according to .htaccess)!! The tool added an AuthUserFile parameter that linked to a .htpasswd file in the same directory as .htaccess. With the new deploy that file obviously was in another directory as it wasn’t defined as shared in Capifony.

It took me quite some time to find that error, so I decided to write some custom Capifony tasks that should help me configure apache based HTTP authentication more easily, which I’d like to share now:

namespace :deploy do
    namespace :auth do

        def file_helper(append = false)
            require 'tempfile'

            htaccess = "#{deploy_to}/shared/web/.htaccess"
            auth = <<EOS
AuthUserFile #{deploy_to}/.htpasswd
AuthGroupFile /dev/null
AuthName ByPassword
AuthType Basic
require valid-user

            Tempfile.open('foo') do |file|
                # Fetch the content of the remote file
                get "#{htaccess}", file.path
                # save the contents temporarily so the
                # auth part can be appended
                content = file.read
                if append then
                    # check if it's already enabled
                    if content.scan(auth).size == 0 then
                        content << auth
                    content.gsub!(auth, "")
                # and now send it back
                put content, "#{htaccess}"
        desc "Enables apache HTTP authentication"
        task :enable do

        desc "Disables apache HTTP authentication"
        task :disable do

        namespace :user do
            htpasswd = "#{deploy_to}/.htpasswd"
            desc "Add a user to the .htpasswd file"

            task :add do
                user = ENV['user']
                password = ENV['password']
                if user.nil? || password.nil? then
                    puts "Usage: deploy:auth:user:add user=$name password=$value"
                # remove the user first
                deploy.auth.user.del user
                run "echo '#{user}:" + password.crypt((rand(99-10)+10).to_s) + "' >> #{htpasswd}"

            desc "Deletes a user from the .htpasswd file"
            task :del do
                user = ENV['user']
                if user.nil? then
                    puts "Usage: deploy:auth:user:add user=$name"
                run "if [ -e #{htpasswd} ]; then sed -i /^#{user}/d #{htpasswd}; fi"

            desc "Clears the .htpasswd file"
            task :clear do
                run ":> #{htpasswd}"

By simply adding the code above to e.g. /app/config/deploy.rb five tasks are added:

  • deploy:auth:enable
  • deploy:auth:disable
  • deploy:auth:user:add user=NAME password=PASSWORD
  • deploy:auth:user:del user=NAME
  • deploy:auth:user:clear

The .htpasswd file will be created at the :deploy_to location, .htaccess at :deploy_to/shared/web/.htaccess, but both can be changed easily. Usage is pretty straightforward:

# create user foo with password bar
cap deploy:auth:user:add user=foo password=bar
# enable http authentication
cap deploy:auth:enable
# ...
# Profit!

I’m open for suggestions and improvements, just drop a line or two. 😉


  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: