Programming in modern Java and C++

Hi! My name is Ján and in this corner of the web I vent about everyday struggles of being a software engineer.

Back

Migrating Apache HTTPd AJP proxy with mod_pagespeed to Nginx

Lots of text, blogs, comparisons and flamewars exist on this topic around the Internet. Some of my favourite when jumping from Apache HTTPd AJP proxy to Nginx are:

  • lower memory footprint
  • no need to spawn new processes (considering prefork on Apache HTTPd)
  • migration to a VPS is cheaper (Nginx consumes less resources, therefore you pay less)
  • it is always good to learn something new
  • it is super cool to say "I am using Nginx" :)

What am I using on Apache that needs to be migrated to Nginx:

  • very simple rewrite (mod_rewrite)
  • AJP proxy (mod_proxy_ajp) with Virtual Hosts
  • SSL / https (mod_ssl)
  • Google Pagespeed (mod_pagespeed)


     +--------------------+          +-----------------------+
     |    Apache HTTPd    |          |    Apache Tomcat      |
     |--------------------|          |-----------------------|
     |                    |          |                       |
     |  mod_proxy_ajp     |          |                       |
     |  mod_pagespeed     +---------->      AJP Connector    |
     |                    |          |                       |
     |                    |          |                       |
     |                    |          |                       |
     |                    |          |                       |
     +--------------------+          +-----------------------+

Buidling Nginx with required modules / extensions on Gentoo

Installing a package from source on Gentoo Linux is super easy because everything is installed (emerged) from source. I was a bit surprised that Nginx needs a special treatment tough. Nginx ebuild located in the portage tree has no USE flags for any additional modules. Luckily there is another way.

For each and every module / addon one wishes to bundle with Nginx, it needs to be recompiled from source. Generaly it means to use a configure directive:


$ # Download ngx_pagespeed @see https://github.com/pagespeed/ngx_pagespeed/
$ cd /usr/src/
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/v1.7.30.3-beta.zip
$ unzip v1.7.30.3-beta.zip # or unzip v1.7.30.3-beta
$ cd ngx_pagespeed-1.7.30.3-beta/
$ wget https://dl.google.com/dl/page-speed/psol/1.7.30.3.tar.gz
$ tar -xf 1.7.30.3.tar.gz # expands to psol/
$ # Download Nginx
$ cd /usr/src/
$ # check http://nginx.org/en/download.html for the latest version
$ wget http://nginx.org/download/nginx-1.4.6.tar.gz
$ tar -xf nginx-1.4.6.tar.gz
$ cd nginx-1.4.6/
$ ./configure --add-module=/usr/src/ngx_pagespeed-1.7.30.3-beta
$ make
$ sudo make install

With Gentoo the procedure is a bit simpler. Just download the addons / modules. Unpack them to a directory (e.g. /usr/src), setup make.conf so that you add NGINX_ADD_MODULES="" variable. In my case I had to add two module paths - one for Nginx AJP and one for Google Pagespeed:


$ cd /usr/src
# Download  and unpack ngx_pagespeed and psol
$ wget https://github.com/pagespeed/ngx_pagespeed/archive/v1.7.30.3-beta.zip
$ unzip v1.7.30.3-beta.zip # or unzip v1.7.30.3-beta
$ cd ngx_pagespeed-1.7.30.3-beta/
$ wget https://dl.google.com/dl/page-speed/psol/1.7.30.3.tar.gz
$ tar -xf 1.7.30.3.tar.gz # expands to psol/
$ cd /usr/src
$ wget https://github.com/yaoweibin/nginx_ajp_module/archive/v0.3.0.zip
$ unzip v0.3.0.zip
# possibly fix ownership and permissions
$ chown -R root:root ngx_pagespeed-1.7.30.3-beta nginx_ajp_module-0.3.0
$ find ngx_pagespeed-1.7.30.3-beta nginx_ajp_module-0.3.0 -type d -exec chmod 755 {} +
$ find ngx_pagespeed-1.7.30.3-beta nginx_ajp_module-0.3.0 -type f -exec chmod 644 {} +
# BEWARE, this will issue a warning during the emerge, if you wish to use these modules, you just need to live with it
$ echo 'NGINX_ADD_MODULES="/usr/src/ngx_pagespeed-1.7.30.3-beta /usr/src/nginx_ajp_module-0.3.0"' >>  /etc/portage/make.conf
# recompile Nginx server
$ emerge -av www-servers/nginx

Nginx should be ready to go now:


$ cd /etc/init.d/nginx start

Visit http://your.server.address/ and see the Nginx test page.

Converting Apache VirtualHost to Nginx VirtualHost

Simplified version of Apache HTTPd VirtualHost config for www.prvaci.eu domain:

$ cat /etc/apache2/vhosts.d/prvaci.eu.conf
<VirtualHost :80>
  ServerName www.prvaci.eu
  ServerAlias prvaci.eu *.prvaci.eu

  ErrorLog /var/log/apache2/prvaci.eu.ajp.error.log
  CustomLog /var/log/apache2/prvaci.eu.ajp.log combined

  RewriteEngine On
  RewriteCond %{HTTP_HOST} ^prvaci.eu [NC]
  RewriteRule ^(.*)$ http://www.prvaci.eu$1 [L,R=301]
  RewriteRule ^(.*);jsessionid=[^\?]+(.*)$ $1$2 [NE,R=301]

  <Proxy *>
    AddDefaultCharset Off
    Order deny,allow
    Allow from all
  </Proxy>

  ProxyPass / ajp://127.0.0.1:8009/
  ProxyPassReverse / ajp://127.0.0.1:8009/

  <IfDefine SSL>
    <IfDefine SSL_DEFAULT_VHOST>
      <IfModule ssl_module>
        <VirtualHost :443>
          SSLEngine on
          #SSLProtocol all -SSLv2
          SSLProtocol -ALL +SSLv3 +TLSv1
          #SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
          SSLCipherSuite HIGH:!SSLv2:!ADH:!aNULL:!eNULL:!NULL
          SSLCertificateFile /etc/ssl/apache2/server.crt
          SSLCertificateKeyFile /etc/ssl/apache2/server.key

          ServerName www.prvaci.eu
          ServerAlias prvaci.eu *.prvaci.eu

          ErrorLog /var/log/apache2/prvaci.eu.ssl.error.log
          CustomLog /var/log/apache2/prvaci.eu.ssl.log combined

          RewriteEngine On
          RewriteCond %{HTTP_HOST} ^prvaci.eu [NC]
          RewriteRule ^(.*)$ https://www.prvaci.eu$1 [L,R=301]
          RewriteRule ^(.*);jsessionid=[^\?]+(.*)$ $1$2 [NE,R=301]
        </VirtualHost>
      </IfModule>
    </IfDefine>
  </IfDefine>
</VirtualHost>

Corresponding version of Nginx VirtualHost configuration:

$ cat /etc/nginx/vhosts.d/prvaci.eu.conf
http {

  upstream tomcats {
    server 127.0.0.1:8009;
    keepalive 10;
  }

  server {
    listen       prvaci.eu:80;
    server_name  prvaci.eu;
    return       301 http://www.prvaci.eu$request_uri;
  }

  server {
    listen       www.prvaci.eu:80;
    server_name  www.prvaci.eu admin.prvaci.eu;
    access_log   /var/log/nginx/prvaci.eu_ajp_access_log;
    error_log    /var/log/nginx/prvaci.eu_ajp_error_log;

    location / {
      rewrite ^(.*)\;[jJ][sS][eE][sS][sS][iI][oO][nN][iI][dD]=[^\?]+(.*)$ $1$2 permanent;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Server $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
      ajp_keep_conn on;
      ajp_pass tomcats;
    }
  }

  server {
    ## IP:Port and server name
    listen        prvaci.eu:444;
    server_name   prvaci.eu www.prvaci.eu admin.prvaci.eu;
    ## SSL log files
    access_log    /var/log/nginx/prvaci.eu_ssl_access_log;
    error_log     /var/log/nginx/prvaci.eu_ssl_error_log;
    ## SSL certificates
    ssl_certificate       /etc/nginx/ssl/prvaci.eu/self-ssl.crt;
    ssl_certificate_key   /etc/nginx/ssl/prvaci.eu/self-ssl.key;

    ## SSL settings
    ssl                   on;
    ## SSL caching/optimization
    ssl_protocols         SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers           HIGH:!SSLv2:!ADH:!aNULL:!eNULL:!NULL;
    ssl_prefer_server_ciphers     on;
    keepalive_timeout             60;
    ssl_session_cache             shared:SSL:10m;
    ssl_session_timeout           10m;
    ## Rest of server config goes here
    location / {
      proxy_set_header            Accept-Encoding         "";
      proxy_set_header            Host                    $http_host;
      proxy_set_header            X-Forwarded-By          $server_addr:$server_port;
      proxy_set_header            X-Forwarded-For         $remote_addr;
      proxy_set_header            X-Forwarded-Proto       $scheme;
      proxy_set_header            X-Real-IP               $remote_addr;
      proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    }
  }
}

Of course one could use a configuration translator, but I find it essential to know what and why is inside my prod configuration. I also managed to make Nginx with pagespeed module working, although it is not performing exactly as Apache with mod_pagespeed does. Especially CSS and JS compression and merging into as single file. Will have to look deeper into it.

Contact

Tell us!
Menu

Items marked with * are required