Project

General

Profile

Actions

Fastcgi on nginx » History » Revision 19

« Previous | Revision 19/31 (diff) | Next »
Nuika Sanders, 05/22/2015 01:36 PM


h1. FastCGI on nginx

h2. About nginx

On paper, nginx is an excellent choice for use as a reverse proxy (together with wthttpd), or for deploying Wt applications using FastCGI, especially if you are using server-initiated updates (server push).

The reason is that nginx, like wthttpd, is completely based on asynchronous I/O, and therefore scales easily to many open connections (unlike other web servers such as Apache, lighttpd, etc.). Server-initiated updates use an open connection for every web client.

We have tested nginx succesfully for both its use as a reverse proxy or for FastCGI deployment of Wt applications. Its FastCGI implementation is a bit clumsy, but newer versions of nginx (>= 0.7.31) than the version currently available in ubuntu should improve on that.

h2. Ubuntu configuration

  • Installing nginx and spawn-fcgi (which comes with lighttpd):

$ sudo apt-get install nginx lig[[http://amodaa.ru/ http]]d

  • Start your application (linked against wtfcgi) using spawn-fcgi. Spawn-fcgi wraps the FastCGI application to listen to a socket or network connection.

$ spawn-fcgi -n -f ../../build/examples/hello/hello.wt -a 0.0.0.0 -p 9091

  • Edit your nginx configuration to redirect a particular URL to your application (replace all occurences of /hello.wt with the path for your application!):

location /hello.wt {
fastcgi_pass 127.0.0.1:9091;

            fastcgi_param  QUERY_STRING       $query_string;
            fastcgi_param  REQUEST_METHOD     $request_method;
            fastcgi_param  CONTENT_TYPE       $content_type;
            fastcgi_param  CONTENT_LENGTH     $content_length;

            if ($document_uri ~ "^/hello.wt/(.*)") {
                    set $apache_path_info /$1;
            }

            fastcgi_param  SCRIPT_NAME        /hello.wt;
            fastcgi_param  PATH_INFO          $apache_path_info;
            fastcgi_param  REQUEST_URI        $request_uri;
            fastcgi_param  DOCUMENT_URI       $document_uri;
            fastcgi_param  DOCUMENT_ROOT      $document_root;
            fastcgi_param  SERVER_PROTOCOL    $server_protocol;

            fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
            fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

            fastcgi_param  REMOTE_ADDR        $remote_addr;
            fastcgi_param  REMOTE_PORT        $remote_port;
            fastcgi_param  SERVER_ADDR        $server_addr;
            fastcgi_param  SERVER_PORT        $server_port;
            fastcgi_param  SERVER_NAME        $server_name;
    }
  • Alternatively to avoid 'if' in declaration just indicate the root of your application:

    location ~ /hello.wt(?/.*|$) {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_NAME /hello.wt;
    fastcgi_param PATH_INFO $path_info;
    include fastcgi_params.conf;
    }

  • Reload (or restart) your nginx server and you are ready to go:

$ sudo /etc/init.d/nginx restart

h2. Debian (Wheezy) configuration

This configuration uses the FastCGI support of nginx, which is enabled in both of the available Debian packages nginx-light and nginx-full. Unlike apache/lighttpd, nginx will not directly spawn the FastCGI application, and so we need an intermediate package to take care of this for us. Fortunately, the end result is very neat, and allows the fastcgi application to be restarted independently of the web server (as well as to easily enable it to run under a different uid).

h3. spawn-fcgi

First, install the spawn-fcgi package:

$ sudo apt-get install spawn-fcgi

This package is responsible for getting the Wt application (a fastcgi application) to listen on a unix socket, which nginx will be configured to talk to. (Note that this does not involve any sort of proxying/copying: spawn-fcgi only needs to set up sockets before executing our application directly).

The application may be started with a command such as:

$ spawn-fcgi -s /var/run/fastcgi-.sock -- /path/to/app.wt

(obviously replacing the paths as appropriate). The environment variable @WT_APP_ROOT@ can, if desired, be set to point to a directory containing @wt_config.xml@. This is also exposed as Wt::WApplication::appRoot().

h3. spawn-fcgi systemd unit files

If using systemd, you can trivially create a unit file under @/etc/systemd/system@, named @/etc/systemd/system/fastcgi-.service@:

[Unit]
Description=FastCGI spawner for amazing Wt web app

[Service]
ExecStart=/usr/bin/spawn-fcgi -s /var/run/fastcgi-.sock \
-P /var/run/fastcgi-.pid \
-u -g -G www-data -M 0660 \
-- /path/to/app.wt
Environment="WT_APP_ROOT=/path/to/app/root"

Type=forking
PIDFile=/var/run/fastcgi-.pid
Restart=always
SyslogIdentifier=fastcgi-

Security-conscious users may wish to research:

PrivateTmp, PrivateDevices, ProtectSystem, ProtectHome

CapabilityBoundingSet=

NoNewPrivileges

[Install]
WantedBy=multi-user.target

Again, replace the paths, usernames etc. as appropriate. In the @ExecStart@ line:

  • @-s @ is the Unix socket over which nginx will contact your application
  • @-P @ is the PID file that will be monitored by systemd (so it must match the @PIDFile=@ line further below in the unit file)
  • @-u @ and @-g @ set the UID/GID to run the application as; this avoids needing to run your application as root at any point
  • @-G www-data@ sets the group for the Unix socket; obviously it must allow read/write access for nginx (which by default uses the @www-data@ group). Since the socket does not have to have the same permissions as the application, this means that nginx can trivially run under a different uid/gid from your application.
  • @-M 0660@ sets the mode on the Unix socket; here we set it to allow group read/write.

The @WT_APP_ROOT@ environment variable is set to allow an application-specific @wt_config.xml@ file to be placed in a specific directory, rather than relying on a system-wide @/etc/wt_config.xml@. The value of this variable is also exposed as Wt::WApplication::appRoot().

Once set up, the service may be enabled at system startup with:

$ sudo systemctl enable fastcgi-.service

It must be started manually for the first time (use @systemctl start@), and may at any time be started/stopped/restarted/disabled in the same manner.

h3. nginx configuration

Under the relevant @server@ section, simply add the following:

location /my/app.wt {
fastcgi_pass unix:/var/run/fastcgi-.sock;
include fastcgi_params;
fastcgi_split_path_info /my/app.wt(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
}

The @fastcgi_pass@ line hands off the connection to our Wt application via the fastcgi protocol over a Unix socket. Obviously adjust the path as appropriate.

In order to get internal paths working properly under all situations (including when the application is installed at the server root), we need to set up a regular expression on the request URI with two captures. The first capture is used as the script name, and the second as the internal path. This is the purpose of the @fastcgi_split_path_info@ line and the @PATH_INFO@ parameter. The first capture is made available as @Wt::WEnvironment::deploymentPath()@ and the second as @Wt::WEnvironment::internalPath()@.

Updated by Nuika Sanders over 9 years ago · 19 revisions