we are looking for a way to point our Apache DocumentRoot to a symlink.
E.g. DocumentRoot /var/www/html/finalbuild
finalbuild should point to a folder somewhere like /home/user/build3
when we move a new build to /home/user/build4 we want to use a shell script that changes the symbolic link "finalebuild" to this new directory /home/user/build4 and do an apache graceful restart to have a new web application version up and running with little risk.
What's the best way to create this symlink and to change this link afterwards using the shell script?
We're using capistrano to employ a similar setup. However, we've run into a few problems:
After switching to the setup, things appeared to be going fine, but then we started noticing that after running cap deploy
, even though the symlink had been changed to point toward the head revision, the browser would still show the old pages, even after multiple refreshes and appending different GET parameters.
At first, we thought it was browser caching, so for development we disabled browser caching via HTTP headers, but this didn't change anything. I then checked to make sure we weren't doing full-page caching server-side, and we weren't. But I then noticed that if I deleted a file in the revision the symlink used to point to, we would get a 404, so Apache was serving up new pages, but it was still following the "old symlink" and serving the pages up from the wrong directory.
This is on shared hosting, so I wasn't able to restart Apache. So I tried deleting the symlink and creating a new one each time. This seemed to work sometimes, but not reliably. It worked probably 25~50% of the time.
Eventually, I found that if I:
- removed the existing symlink (deleting it or renaming it);
- made a page request, causing Apache to attempt to resolve the symlink but find it missing (resulting in a 404)
- then created a new symlink to the new directory
it would cause the docroot to be updated properly most of the time. However, even this isn't perfect, and about 2-5% of the time, when the deploy script ran wget
to fetch a page right after renaming the old symlink, it would return the old page rather than a 404.
It seems like Apache is either caching the filesystem, or perhaps the mv
command only changed the filesystem in memory while Apache was reading from the filesystem on disk (doesn't really make any sense). In either case, I've taken up someone's recommendation to run sync
after the symlink changes, which should get the filesystem on disk in sync with memory, and perhaps the slight delay will also help the wget
to return a 404.
I've used symlinks as the apache DocumentRoot in production with no graceful restart necessary. In general, the idea should work. A 403 error probably indicates a permissions error unrelated to the symlink changing. An added wrinkle that you would want to add is making the symlink switch atomic so the symlink always exists. That is to say, at no time is the symlink nonexistent, even for a moment.
The solution to this problem is to effect the change by creating a new symlink and then renaming it over the old symlink. On Unix-like systems, renaming is an atomic operation, and thus the symlink “change” will be atomic too. By hand, the process looks like this:
$ ln -s new current_tmp && mv -Tf current_tmp current