diff options
Diffstat (limited to 'site/src/docs/apache.page')
-rw-r--r-- | site/src/docs/apache.page | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/site/src/docs/apache.page b/site/src/docs/apache.page new file mode 100644 index 0000000..ab26510 --- /dev/null +++ b/site/src/docs/apache.page @@ -0,0 +1,481 @@ +--- +title: Apache +inMenu: true +directoryName: Apache +--- + +h1. Apache Best Practice Deployment + +h3. By Charles Brian Quinn + +The preferred setup (for now) is to put Mongrel behind an Apache 2.2.3 +server running mod_proxy_balancer. Apache is a proven web server, runs +half the Internet, and is a pain to configure. These instructions should +get you started, but refer to the Apache folks for anything more complex +or weird. + +When you're just starting out, don't bother with doing anything but +running just Mongrel. Mongrel is slower than Apache, but not so slow that +small installations will notice it. The worst thing you can do is +try to learn Apache install when you're also trying to learn Ruby on Rails +and Mongrel too. Start small, then *when you need*, build up to the big stuff. + +h2. A simple single mongrel configuration + +Start up a single mongrel instance on port 8000: + +<pre><code> + $ mongrel_rails start -d -p 8000 \ + -e production -P /full/path/to/log/mongrel-1.pid +</code></pre> + +Now, we'll tell Apache to simply proxy all requests to the mongrel server +running on port 8000. Simply add the following to your httpd.conf or in +a vhost.conf file: + +<pre><code> + <VirtualHost *:80> + ServerName myapp.com + ServerAlias www.myapp.com + + ProxyPass / http://www.myapp.com:8000/ + ProxyPassReverse / http://www.myapp.com:8000 + ProxyPreserveHost on + </VirtualHost> +</code></pre> + +That's it, in a nutshell. Several things to note in this configuration: + +1) This configuration forwards all traffic to mongrel. This means mongrel +will serve images, javascript, files, and everything else. It's quite fast +at this, but Apache can do it better. + +Here are some basic proxypass rules you can add to tell the ProxyPass not +to forward on requests to certain documents/requests: + +<pre><code> +ProxyPass /images ! +ProxyPass /stylesheets ! +#continue with other static files that should be served by apache + +Alias /images /path/to/public/images +Alias /stylesheets /path/to/public/stylesheets +#continue with aliases for static content +</code></pre> + +For a more detailed set of rules for forwarding on all dynamic content to mongrel, +see the more detailed configuration below for more details. + +2) In this configuration, it is entirely possible that two users (web +requests) could hit your application at the exact same time, and one would +have to wait literally milliseconds until the first request is finished +before having a turn at the mongrel instance. Unless you've got some really +long HTTP processes, the nature of the HTTP protocol is pretty good at waiting +in line. Only you can determine ("through metrics":http://mongrel.rubyforge.org/docs/how_many_mongrels.html) how long and +how many users will come at your application at the exact same time. + +Sufficient to say, if you're ready to start scaling with multiple mongrel +instances, read on. + +h2. Using multiple mongrel instances with mod_proxy_balancer + +First, let's start up a few mongrel instances (*nix-style): + +<pre><code> +$ mongrel_rails start -d -p 8001 \ + -e production -P log/mongrel-1.pid +$ mongrel_rails start -d -p 8002 \ + -e production -P log/mongrel-2.pid +$ mongrel_rails start -d -p 8003 \ + -e production -P log/mongrel-3.pid +$ mongrel_rails start -d -p 8004 \ + -e production -P log/mongrel-4.pid +</code></pre> + +You can also use "mongrel_cluster":http://mongrel.rubyforge.org/docs/mongrel_cluster.html by "Bradley Taylor":http://fluxura.com/ for +managing several mongrel instances with a configuration file (and sysv init +scripts for *nix servers). + +We're going to be requiring the use of mod_proxy_balancer, a "new feature":http://httpd.apache.org/docs/2.2/new_features_2_2.html in +Apache 2.1/2.2 and above to proxy requests to +our mongrel instances. This software based HTTP load balancer will distribute +requests evenly (applying a weighting and selection algorithm) to our mongrel +instance(s). It even comes with a swell load-balancing manager page for +monitoring incoming requests. For more information, see: +"Apache's mod_proxy_balancer Documentation":http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html. + +h2. Obtaining Apache 2(.1+) + +I won't go into too many details, as windows and the various linux +distributions all have several methods for obtaining apache2, but you will need +the use of the following modules: + + * mod_proxy, mod_proxy-html, and mod_proxy_balancer + * mod_rewrite + * mod_deflate + * mod_headers + * (optional) mod_cache and one of mod_memcache or mod_filecache + * (optional) mod_ssl + +If you're compiling from source, this configuration should do the trick: + +<pre><code> +#./configure --enable-deflate --enable-proxy --enable-proxy-html \ +--enable-proxy-balancer --enable-rewrite --enable-cache \ +--enable-mem-cache --enable-ssl --enable-headers +</code></pre> + +h2. Configuring Apache2 + +A good practice is the separation of apache configuration files. Recommended +by several other good guides, we'll be storing information for our application +in several different files. Put these files somewhere that apache2 knows +about. Apache is quite good about scanning for all .conf files in certain +directories. + +h3. myapp.common + +Apache lets you include common configuration items into another configuration +so you can cut down on repetition. What we're going to do is make a file +that has all the common junk that every Mongrel application needs to +work at all, then we'll just include this in little .conf files for +any application we deploy. + +Notice that this file doesn't end in .conf since it's not a real configuration +file, but you can name it however you wish. + +<b>Important Update: "typo fixed in IE deflate rules":http://rubyforge.org/pipermail/mongrel-users/2006-October/001868.html</b> + +<pre><code> + ServerName myapp.com + DocumentRoot /var/www/myapp.com/current/public + + <Directory "/var/www/myapp.com/current/public"> + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + </Directory> + + RewriteEngine On + + # Uncomment for rewrite debugging + #RewriteLog logs/myapp_rewrite_log + #RewriteLogLevel 9 + + # Check for maintenance file and redirect all requests + # ( this is for use with Capistrano's disable_web task ) + RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f + RewriteCond %{SCRIPT_FILENAME} !maintenance.html + RewriteRule ^.*$ /system/maintenance.html [L] + + # Rewrite index to check for static + RewriteRule ^/$ /index.html [QSA] + + # Rewrite to check for Rails cached page + RewriteRule ^([^.]+)$ $1.html [QSA] + + # Redirect all non-static requests to cluster + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L] + + # Deflate + AddOutputFilterByType DEFLATE text/html text/plain text/css + # ... text/xml application/xml application/xhtml+xml text/javascript + BrowserMatch ^Mozilla/4 gzip-only-text/html + BrowserMatch ^Mozilla/4.0[678] no-gzip + BrowserMatch \bMSIE !no-gzip !gzip-only-text/html + + # Uncomment for deflate debugging + #DeflateFilterNote Input input_info + #DeflateFilterNote Output output_info + #DeflateFilterNote Ratio ratio_info + #LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate + #CustomLog logs/myapp_deflate_log deflate +</code></pre> + +h3. myapp.conf + +We then take the above commmon file and include it in our configuration file +for this application deployment. + +If you're using virtual hosting (a pretty good idea, even when you're the only +one on the server), your sample configuration can be this simple: + +<pre><code> + <VirtualHost *:80> + Include /etc/httpd/conf.d/myapp.common + + ErrorLog logs/myapp_errors_log + CustomLog logs/myapp_log combined + </VirtualHost> +</code></pre> + +h3. myapp.proxy_cluster.conf + +This is the meat of our configuration, and goes hand in hand with our mongrel +(or mongrel_cluster) configuration. This configuration tells the apache2 +mod_proxy_balancer to proxy requests to 3 mongrel instances running on ports +8000, 8001, and 8002. + +<pre><code> + <Proxy balancer://mongrel_cluster> + BalancerMember http://127.0.0.1:8000 + BalancerMember http://127.0.0.1:8001 + BalancerMember http://127.0.0.1:8002 + </Proxy> +</code></pre> + +If you had an seperate application server, you could balance to it easily by +replacing the 127.0.0.1 with the ip or hostname of your application server, but +be sure to make them listen on an external interface (rather than 127.0.0.1). + +When you add an additional mongrel to your mongrel_cluster, you can simply add +an additional BalancerMember to this file, restart apache (or reload) and +you're all set. + +h3. (optional) myapp.proxy_frontend.conf + +This optional file will setup the balancer-manager -- a simple front-end for +viewing how your requests are being handled. This balancer in the +configuration below will only work from the localhost, so no one else (or +possibly you) can view it unless you alter the "Deny" and "Allow" lines. + +<pre><code> +Listen 8080 +<VirtualHost *:8080> + <Location /> + SetHandler balancer-manager + Deny from all + Allow from localhost + </Location> +</VirtualHost> +</code></pre> + +h3. SSL Requirements + +In order for mongrel to know that this request has a forwarded protocol of +https, we'll need to add a special header (hence the addition of mod_header, +included in most apache2 builds). + +<pre><code> + Include /etc/httpd/conf.d/myapp.common + + # This is required to convince Rails (via mod_proxy_balancer) that we're + # actually using HTTPS. + RequestHeader set X_FORWARDED_PROTO 'https' +</code></pre> + +You need this mostly so that redirects go back to https and so you can +spot when people are coming through SSL or not. + +h2. Automation, Automation, Automation + +There are several great tools that automate the setup of Apache for use with +mongrel and mongrel_cluster. The "RailsMachine gem":https://support.railsmachine.com/index.php?pg=kb.chapter&id=18 can +automate an entire setup of a Rails application. Also, "Slingshot Hosting":http://www.slingshothosting.com/ has +a sample set of "Capistrano recipes":http://www.slingshothosting.com/support/capistrano that automatically setup Apache2 and mongrel +through the @rake remote:setup@ task. Be sure to check out both for some ideas. + +h2. Running Multiple Rails Apps with Mongrel + +The newest version of Mongrel supports multiple Rails applications through +the use of the --prefix command. The Apache magic for proxying a +single application is here assuming your prefix is app1: + +<pre><code> +ProxyPass /app1 http://127.0.0.1:3000/app1 +ProxyPassReverse /app1 http://127.0.0.1:3000/app1 +</code></pre> + +You need to have the proxy pass the new directory name. + +Thanks to Joey Geiger and others of the mongrel list for these +instructions. + +h2. Success Stories + +Martins on the mongrel-list has submitted this simple apache configuration. It serves up static content with apache, and forwards dynamic content on to mongrel using ProxyPass. Thanks Martins: + +<pre><code> +<VirtualHost *> + ServerName myapp.tld + ServerAlias www.myapp.tld + + DocumentRoot /var/www/sites/myapp/current/public + + <Directory "/var/www/sites/myapp/current/public"> + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + </Directory> + + RewriteEngine On + + # Check for maintenance file. Let apache load it if it exists + RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f + RewriteRule . /system/maintenance.html [L] + + # Let apache serve static files + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f + RewriteRule (.*) $1 [L] + + # Don't do forward proxying + ProxyRequests Off + + # Enable reverse proxying + <Proxy *> + Order deny,allow + Allow from all + </Proxy> + + # Pass other requests to mongrel instance + ProxyPass / http://127.0.0.1:8200/ + ProxyPassReverse / http://127.0.0.1:8200/ + +</VirtualHost> +</code></pre> + +Phillip Hallstrom has submitted this apache configuration, which includes support for having static directories handled by Apache, php support, and hiding svn directories. + +<pre><code> +<VirtualHost *:80> + + ServerName myserver.com + DocumentRoot /path/to/my/app/public + + <Directory "/path/to/my/app/public"> + Options FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + </Directory> + + <Proxy balancer://mongrel_cluster> + BalancerMember http://127.0.0.1:8805 + </Proxy> + + RewriteEngine On + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d + RewriteRule ^(.+[^/])$ $1/ [R] + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} \.php + RewriteRule ^(.*)$ $1 [QSA,L] + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.html -f + RewriteRule ^(.*)$ $1/index.html [QSA,L] + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.php -f + RewriteRule ^(.*)$ $1/index.php [QSA,L] + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d + RewriteRule ^(.*)[^/]$ $1/ [QSA,L] + + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f + RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L] + + AddOutputFilterByType DEFLATE text/html + AddOutputFilterByType DEFLATE application/x-javascript + AddOutputFilterByType DEFLATE text/css + AddOutputFilterByType DEFLATE text/plain + AddOutputFilterByType DEFLATE text/xml + AddOutputFilterByType DEFLATE application/xml + AddOutputFilterByType DEFLATE application/xhtml+xml + + BrowserMatch ^Mozilla/4 gzip-only-text/html + BrowserMatch ^Mozilla/4.0[678] no-gzip + BrowserMatch bMSIE !no-gzip !gzip-only-text/html + + php_value include_path /path/to/my/app/php:/usr/local/lib/php:. + php_value auto_prepend_file /path/to/my/app/php/auto_prepend.php + + # this not only blocks access to .svn directories, but makes it appear + # as though they aren't even there, not just that they are forbidden + <DirectoryMatch "^/.*/\.svn/"> + ErrorDocument 403 /404.html + Order allow,deny + Deny from all + Satisfy All + </DirectoryMatch> + +</VirtualHost> +</code></pre> + +Jens Kraemer reports this differing proxy setup that uses the P option in Rewrite rules so as not to use the ProxyPass directive: + +<pre><code> + # Don't do forward proxying + ProxyRequests Off + + # Enable reverse proxying + <Proxy *> + Order deny,allow + Allow from all + </Proxy> + + RewriteEngine On + + # Check for maintenance file. Let apache load it if it exists + RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f + RewriteRule . /system/maintenance.html [L] + + # Rewrite index to check for static + RewriteRule ^/$ /index.html [QSA] + + # Let apache serve static files (send everything via mod_proxy that + # is *no* static file (!-f) + RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f + RewriteRule .* http://127.0.0.1:8200%{REQUEST_URI} [L,P,QSA] +</code></pre> + +the P option to the last rule replaces the ProxyPass and +ProxyPassReverse directives. + + +h2. SVN Security + +If you use svn to issue checkouts instead of exports, you'll need to hide those pesky .svn directories. This works: + +<pre><code> +# this not only blocks access to .svn directories, but makes it appear + # as though they aren't even there, not just that they are forbidden + <DirectoryMatch "^/.*/\.svn/"> + ErrorDocument 403 /404.html + Order allow,deny + Deny from all + Satisfy All + </DirectoryMatch> + +</VirtualHost> +</code></pre> + +h2. Reading REMOTE_USER from mongrel through proxy + +Jon Reads reports successfully reading the REMOTE_USER variable: + +After many hours trying to solve the same problem I found this post: "Forcing a proxied host to generate REMOTE_USER":http://www.nabble.com/Forcing-a-proxied-host-to-generate-REMOTE_USER-tf1114364.html#a2914465 + +and can confirm that the following works for me when put in the Proxy +directive on Apache 2: + +<pre><code> + RewriteEngine On + RewriteCond %{LA-U:REMOTE_USER} (.+) + RewriteRule . - [E=RU:%1] + RequestHeader add X-Forwarded-User %{RU}e +</code></pre> + +h2. References and Other Guides + +[1] "Time For A Grown-Up Server: Rails, Mongrel, Apache, Capistrano and You":http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/ + +[2] "Bradley Taylor's Fluxura":http://fluxura.com/ and "RailsMachine":http://www.railsmachine.com/ + +[3] "Slingshot Hosting Automated Capistrano Recipe":http://www.slingshothosting.com/support/capistrano + +Thanks to many users on the mongrel list for making it easy for me to compile all these tips and tricks as they come across the list. + |