THIS PAGE IS OLD AND NO LONGER RELEVANT
- 1 Apache
- 2 Mongrel
- 3 Apache, compressed
- 4 Apache, cachable
- 5 Allow non-ssl for assets
- 6 Putting it all together
Apache¶
Install apache:
# apt-get install apache2
Make it so /etc/init.d/apache2 will start apache:
codetitle. /etc/defaults/apache2
NO_START=0
Enable 443 so we can do SSL:
codetitle. /etc/apache2/ports.conf
Listen 80
Listen 443
Enable the needed apache modules:
# a2enmod rewrite
# a2enmod proxy
# a2enmod proxy_http
# a2enmod proxy_balancer
# a2enmod ssl
# a2enmod headers
Set up the basic VirtualHost sections, requiring SSL connection:
codetitle. /etc/apache2/conf.d/we.riseup.net
<VirtualHost we.riseup.net:80>
ServerName we.riseup.net
RedirectMatch (.*)$ https://we.riseup.net$1
</VirtualHost>
<VirtualHost we.riseup.net:443>
SSLEngine on
SSLCertificateKeyFile /etc/certs/we.riseup.net/key.pem
SSLCertificateFile /etc/certs/we.riseup.net/cert.pem
RequestHeader set X_FORWARDED_PROTO 'https'
ServerName we.riseup.net
DocumentRoot /usr/apps/crabgrass/current/public
<Directory "/usr/apps/crabgrass/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
The X_FORWARDED_PROTO is needed when using mongrel in order for rails to think that it is really serving https.
Test the apache configuration:
# apache2ctl configtest
If that works, re/start apache:
/etc/init.d/apache2 stop
/etc/init.d/apache2 start
If everything worked, you should be able to browse to static files like /javascripts/prototype.js
.
Mongrel¶
Mongrel is mini web server written in ruby. It is designed to be a wrapper around ruby applications to give them a long lived process to call home. Instead of using the archaic cgi interface, mongrel communications with apache over plain old http. All requests for static files will go to apache, and requests for the web application will get passed on to one of three mongrel processes, which will in turn pass the request on to our rails web application. We could set up mongrel to be our web server instead of apache, but apache is better at serving static files and allows us the possibility of setting up many backend mongrel/rails processes (possibly on other servers).
Install mongrel:
# aptitude install ruby1.8-dev build-essential
# gem install mongrel -y --no-rdoc --no-ri
# aptitude remove build-essential
Create a generic setup for a rails application:
codetitle. /etc/apache2/rails.conf
RewriteEngine On
# 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]
To activate this configuration for a particular VirtualHost
, add Include /etc/apache2/rails.conf
.
This configuration will let static files be served from disk, and all other requests will be sent to mongrel_cluster
. What is mongrel_cluster
? Lets define it:
codetitle. /etc/apache2/conf.d/mongrel-cluster
<Proxy balancer://mongrel_cluster>
Order allow,deny
Allow from all
BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
BalancerMember http://127.0.0.1:8002
</Proxy>
What have we done? When a request comes in that is not a static file, it is passed to balancer::mongrel_cluster
. We have defined this to then proxy the connection to localhost on one of three ports where we have our mongrel mini-web-server running. By default, if you have mongrel installed, then starting the rails spawner will start three mongrel processes listening on 8000, 8001, and 8002.
To start, restart, stop, and get the status of the mongrel processes:
crabgrass@we% /usr/apps/crabgrass/current/script/process/spawner
crabgrass@we% /usr/apps/crabgrass/current/script/process/reaper
crabgrass@we% /usr/apps/crabgrass/current/script/process/reaper -a kill
crabgrass@we% /usr/apps/crabgrass/current/script/process/inspector
Mongrel can run as whatever user you want. Typically, your rails application will have its own user that is different from www-data. Mongrel should be started and stopped using that user. In our case, the user crabgrass
owns all crabgrass web application files.
Now that mongrel is running, restart apache and everything should be working.
Debugging mod_rewrite:
codetitle. /etc/apache2/rails.conf
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 9
# touch /var/log/apache2/rewrite.log
# /etc/init.d/apache2 restart
Apache, compressed¶
The module mod_deflate will automatically send text files in a compressed format to web browsers that support it. This will often reduce the size of a file by 50-80%.
Enable the deflate module:
# a2enmod deflate
Create a generic configuration for deflate:
codetitle. /etc/apache2/deflate.conf
AddOutputFilterByType DEFLATE application/x-javascript text/html text/plain text/css text/javascript text/xml
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Now we can just add Include /etc/apache2/deflate.conf
to any VirtualHost
or Location
section we want to serve compressed files.
If you want to debug deflate, you can add this too:
codetitle. /etc/apache2/deflate.conf
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 /var/log/apache2/deflate.log deflate
# touch /var/log/apache2/rewrite.log
# /etc/init.d/apache2 restart
Apache, cachable¶
The web browser will do its darnedest to cache static content when it can. However, it could use help. In our case, we have a lot of small avatar files with unique URLs: if the image changes, then the avatar will be different. So we would like to cache images for a very long time. The module mod_expire lets you specify how long certain content types should be cached for.
Enable mod_expire
# a2enmod expire
Create a generic configuration for mod_expire:
codetitle. /etc/apache2/expire.conf
<IfModule mod_expires.c>
# turn on the module for this directory
ExpiresActive on
# cache common graphics for 3 days
ExpiresByType image/jpg "access plus 3 days"
ExpiresByType image/gif "access plus 3 days"
ExpiresByType image/jpeg "access plus 3 days"
ExpiresByType image/png "access plus 3 days"
# cache css and javascript forever
ExpiresByType text/javascript "access plus 10 years"
ExpiresByType application/x-javascript "access plus 10 years"
ExpiresByType text/css "access plus 10 years"
ExpiresDefault "access plus 24 hours"
</IfModule>
To use this mod_expire configuration, put Include /etc/apache2/expire.conf
in a Directory
section in your apache config.
Caching forever for js and css is good in our case, because these assets will get a new url if they change.
Allow non-ssl for assets¶
Firefox will not cache anything on disk that came via ssl, but we would really really like firefox to disk cache the css and js.
So, instead of just redirecting all traffic from http to https, we do it selectively:
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/bundles/
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=permanent,L]
This will redirect anything that is not /bundles/ to https. The way this particular rails application is written, /bundles/ will get handled by rails the first time, but subsequent loads will be statically cached.
This is what it looks like in the VirtualHost:
<VirtualHost we.riseup.net:80>
ServerName we.riseup.net
DocumentRoot /usr/apps/crabgrass/current/public
<Directory "/usr/apps/crabgrass/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
Include /etc/apache2/expire.conf
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/bundles/
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=permanent,L]
Include /etc/apache2/rails.conf
Include /etc/apache2/deflate.conf
</VirtualHost>
The order matters: the ssl redirect must come before the rails.conf.
Putting it all together¶
codetitle. /etc/apache/conf.d/we.riseup.net
<VirtualHost we.riseup.net:80>
ServerName we.riseup.net
DocumentRoot /usr/apps/crabgrass/current/public
<Directory "/usr/apps/crabgrass/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
Include /etc/apache2/expire.conf
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/bundles/
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=permanent,L]
Include /etc/apache2/rails.conf
Include /etc/apache2/deflate.conf
</VirtualHost>
<VirtualHost we.riseup.net:443>
SSLEngine on
SSLCertificateKeyFile /etc/certs/we.riseup.net/key.pem
SSLCertificateFile /etc/certs/we.riseup.net/cert.pem
RequestHeader set X_FORWARDED_PROTO 'https'
ServerName we.riseup.net
DocumentRoot /usr/apps/crabgrass/current/public
<Directory "/usr/apps/crabgrass/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
Include /etc/apache2/expire.conf
</Directory>
Include /etc/apache2/rails.conf
Include /etc/apache2/deflate.conf
</VirtualHost>
codetitle. /etc/apache2/rails.conf
RewriteEngine On
# 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]
codetitle. /etc/apache2/conf.d/mongrel-cluster
<Proxy balancer://mongrel_cluster>
Order allow,deny
Allow from all
BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
BalancerMember http://127.0.0.1:8002
</Proxy>
codetitle. /etc/apache2/deflate.conf
AddOutputFilterByType DEFLATE application/x-javascript text/html text/plain text/css text/javascript text/xml
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
codetitle. /etc/apache2/expire.conf
<IfModule mod_expires.c>
# turn on the module for this directory
ExpiresActive on
# cache common graphics for 3 days
ExpiresByType image/jpg "access plus 3 days"
ExpiresByType image/gif "access plus 3 days"
ExpiresByType image/jpeg "access plus 3 days"
ExpiresByType image/png "access plus 3 days"
# cache css and javascript forever
ExpiresByType text/javascript "access plus 10 years"
ExpiresByType application/x-javascript "access plus 10 years"
ExpiresByType text/css "access plus 10 years"
ExpiresDefault "access plus 24 hours"
</IfModule>