Ask HN: How do you deploy your PHP apps to production?

50 points by smharris65 ↗ HN
I have several php applications for various projects and the code is deployed in production using either rsync or subversion. But I want all apps to be deployed with scripts using one method for consistency. Which methods have been successful for you?

56 comments

[ 2.9 ms ] story [ 112 ms ] thread
We have a script that tars up projects or specific files and uploads them and puts them in place, but lately we've been moving towards plain svn.

If it were up to me, it'd be git, with separate branches for production and beta for easy merging.

ftp a tarball then untar, or rsync.
I use git, with three levels, dev (active development), stage (current stable version), and production. All three have different branches. Then I have a bash script that configures them accordingly.
We use Trunks (http://www.trunksapp.com) to host our SVN repos, then have post-commit hook fire an HTTP request to the production staging server to check out the latest revision.

We manually initiate an export from the live server, although we likely will look in the commit message for a keyword (like [live]) and initiate from there.

Git or rsync
Beanstalk Hosted SVN/GIT has deployment tools. I haven't used them as I do my pulls manually.
bash script checks out SVN code, then uses a configuration file to build bundles of JS and CSS files using YUI-compressor, and add query string timestamps to CSS images for cache busting. After all that, the code is rsync'd to various web servers
Capistrano, despite being written in Ruby, will deploy PHP. I've used it to deploy WordPress and SMF installs once or twice. The advantage here is that you don't have to choose git over svn or any CVS for that matter. You can keep your configs separate and link them in.
+1 for Capistrano, we use it to deploy Rails, Sinatra, and PHP apps. gem install capistrano-ext and you can do easy multi-stage deploys (deploy a different branch to your staging/testing/beta server by doing cap staging deploy vs. cap production deploy for example). More details here: http://weblog.jamisbuck.org/2007/7/23/capistrano-multistage
Capistrano + Git. Works beautifully, and rolling back bad deployments is a breeze
We use Mercurial here. Easy, secure (ssh with keys) never forget files, small transfer size, possibility of committing regularly when the client has access to the files. With hooks, the update is done as soon as the changesets are received.

In some cases we can even create websites on the fly with a simple "hg clone"

I guess Git allows more or less the same workflow but Mercurial is easier for your designers.

Yes, I do basically this, but with Git.
I started to use http://www.deployhq.com/. I was already using their http://codebasehq.com for GIT hosting. Works great, server does not even need to have GIT installed, it can use ftp or ssh.
Upvoted, I've been checking this out recently. As a codebase customer they sent me a free account to deployHQ and it seems pretty nice. It has an API (with a rubygem) so you can integrate it into your scripts to achieve whatever level of fancyness you need.

I'm also looking into the possibilities around having a 'deploy' or 'production' branch in git, and a post-commit hook that automatically deploys (with another script obviously) any commits to that branch. This is how heroku works and it's much cleaner than capistrano in my eyes.

I deploy my CodeIgniter apps via the Springloops hosted SVN service.
Since I'm only updating one PHP app at a time, I commit my changes to the SVN repo, then SSH into the server and update.
We have build scripts for phing, exports from subversion, migrates the database, loads stored procs, triggers and views, creates symlinks for data here and there, creates our dojo build layers, and builds a couple of executables we need.

Capistrano is better for the simple stuff, but once we started doing more we moved to phing.

We have a bash script which grabs the latest Phing config/property files and then Phing handles the rest...

* calls YUI Compressor to minify css/js * calls a custom script to upload images to the CDN * calls dbdeploy to update our staging database * symlinks the "built" revision to our staging site

When we push a build from staging to production, we run a small bash script that calls Phing which symlinks the desired revision to the production site.

+1 Phing. We use Phing for deploying to production and deploying a staging instance of the app.

Phing can checkout from SVN, run a mysqldump to snapshot the DB, modify text files (i.e. different .htaccess files for staging/production), run arbitrary shell commands and ping web-APIs for notification etc.

Deploys take between 10 and 30 seconds.

I deploy a large symfony php app with capistrano.

The only big change I needed to add was to tell it not to run the server restarting code, other then that it wasn't that hard.

Rollback support, and the fact that I don't have to login to the server and run commands each time I deploy is great.

I've tried out a few different tools now; the only two I've had any real success with were Capistrano and Fabric.

Capistrano works well, great git integration, but it does have some rails-isms you need to override to make it work sanely. The capistrano-php extension can help with that: http://github.com/namics/capistrano-php but you'll need to use gem to manage it. You'll also definitely want the multistage plugin which doesn't come standard. There were some bugs present in the CVS integration which may be a problem depending on your source control system.

I've also tried Fabric: http://docs.fabfile.org/0.9.2/ I liked the tool. I found it a bit more low level then Capistrano but also a little simpler to work with. It comes prepackaged (albeit an older version) in Ubuntu without any dependencies other than stock python which our sysadmin preferred to using Ruby gems. I do recommend the new version found in pip though. The two main problems with Fabric are its lack of any integration plugins and the Paramiko SSH library it uses has no support for SSH key forwarding (there is a workaround: http://lincolnloop.com/blog/2009/sep/22/easy-fabric-deployme... but it has its own set of problems).

In the end, neither worked out for me. Capistrano had to much of a learning curve for my co-workers and Fabric wouldn't work with our SSH setup. For now, I'm using a script in our working directory that I SSH to, run, and it updates the code in place. Crude, but ultimately effective. That said, definitely looking forward to a replacement.

I was using Capistrano too but, like you, couldn't get my co-workers up-and-running with it so we switched to using Phing. I didn't want to be the only one doing deployments at work.
hey thanks - we were trying to figure out between cap and fabric and your answer was of big help.
I used to be a PHP developer (Python only now) but I still used Fabric extensively. Rsync is invaluable, tying it in with fabric makes for a pretty useful deployment tool.
Right now I'm using symfony php framework that deploys the code to whatever server I want(uses rsync and you must have access to ssh on that server). All the projects are kept in svn repo's.

I can imagine writing a script that just runs every so often to sync the staging server to the production server, however I don't really care for this method because I want more control. I may change my mind in the future.

For some internal applications that I work on at work, we deploy them using the good ol' "svn up". I really don't like this method for a ton of reasons. The first reason being I can just goto http://www.example.com/.svn and see all the svn files.

I think the best by far is using rsync. Some things that I have done with rsync is configure the database settings in a config file, then just have rsync ignore that file so I can set different database settings for dev/staging servers.

For personal projects I usually have them on a private space on Assembla, which one of the options is they allow you to FTP your code to a server. I haven't used it myself, but I can see where this would be useful.

You could use a .htaccess file to prevent the .svn directory from being accessible, I would think
I use git with a remote repository to which you can push (and pull) stuff easily.
I do this as well, for 5 websites based on a custom PHP microframework. Git kicks ass!
Subversion -- the website is a working copy of the production branch and I just do an svn update when changes need to be deployed.

The whole thing is wrapped up in a script that makes it possible to one-click deploy changes.

The biggest thing is the application is directory independent and auto-senses the host for database selection. This means that no changes are required to the application to run it in development, staging, or production.

Edit: Apache is setup so that no .svn directories are served. Given that most web applications go through a front-controller now, I'm hoping this isn't as much of a concern anymore.

Same here, but Mercurial instead of Subversion.
Same here, not as nicely automated though (still need to actually type 'svn update').

What I really like is the ability to instantly roll back to any version.

Don't forget to block .svn directories in your apache config!

The other advantage is sometimes, in emergency situations, I've had to edit the production code directly on the server. It's nice to be able to see what's changed, commit if necessary, or rollback to the original production version.
umm, isn't that what svn export is for :)

why stop at .svn, how about .~, .bak, .tmp, .swp !

The problem with export is that you're deploying every single file. With svn update, you're only deploying the changed files.
(comment deleted)
Just a word of advice to anybody using this approach - make sure to setup Apache(et al) to not serve .svn folders and files or someone will be able to download your code. I've always used a release shell script that does an svn export and just replaces the entire directory.
Or, better yet, don't put sensitive data in public web directories! Have your working copy somewhere else, and update your "svn update" script to also run an rsync with an --exclude=.svn to your web root.
We use Subversion as well. However, we use Ant scripts to do the build work. It makes updating our servers pretty straight forward.
My sites are PHP so building is limited but some things do need to be built. However, my sites effectively build themselves without the need for another tool. On the first access of a resource, if the target doesn't exist it's built by the code automatically and stored in a cache. During development, the cache is disabled so you can edit and run without any intermediate build step. Things built this way include parts of the ORM and output templates.
Same here, multiple sites. Using the same code base for dev/stage/production is a huge win.
svn up

simple.

priceless.

Work: rdist over ssh Personal projects: rsync over ssh

In both cases I use a wrapper script to make the push as simple as possible. At work I push from the dev server to prod, at home I push from my desktop to either dev or (dev and prod).

In both case I use RCS for version control.