Configure CppCMS to run with different web servers
Introduction
There are many options to connect CppCMS application to web server:
Protocol: you can use FastCGI or SCGI protocols, you can also run over HTTP protocol behind proxy.
Recommendation: use FastCGI as it has best support over various web servers.
Application start: it can be started by the web server and controlled by it or it can run as independent service when web server only connects to it.
Communication method: you can use Unix domain sockets or tcp/ip sockets. For local communication unix sockets are preferred.
Please note, this tutorial is provided for running CppCMS based systems in production environment.
It is less friendly for debugging. If you want to debug
your application behind web server, use cppcms_run
utility which allows you to prepare web server configurations automatically and run web servers themselves.
It allows you to run your web application behind 3 most popular web servers: Apache, Lighttpd and Nginx using FastCGI, SCGI protocols or use them as Reverse HTTP Proxy.
Using HTTP Protocol
CppCMS provides basic implementation of HTTP protocol and thus it can run behind reverse HTTP Proxy or be used in embedded environments. This option is not recommended for use in production environment as internal web server has quite weak performance in serving static files and it is very limited options in comparison to widely used web servers.
Assumptions
In all our examples we assume:
- Application's executable placed in
/opt/app/bin/hello
- Application's configuration file placed in
/opt/app/etc/config.js
- The document root is
/var/www
- Our application's URL (script) is
/hello
Lighttpd
Lighttpd supports both fastcgi/scgi protocols over unix and tcp/ip sockets. It can start the application for you and use external FastCGI/SCGI application.
Lighttpd, FastCGI
Lighttpd, FastCGI, Start by Web Server
You should enable mod-fastcgi and then use this Configuration file:
fastcgi.server = ( ## The script name of the application "/hello" => (( ## Command line to run "bin-path" => "/opt/app/bin/hello -c /opt/app/etc/config.js", "socket" => "/tmp/hello-fcgi-socket", ## Important - only one process should start "max-procs" => 1, "check-local" => "disable" )) )
CppCMS configuration:
{ "service" : { "api" : "fastcgi", "socket" : "stdin" // use server's socket } }
Lighttpd, FastCGI, External Start
You should enable mod-fastcgi and then use this Configuration file:
fastcgi.server = ( ## The script name of the application "/hello" => (( "socket" => "/tmp/hello-fastcgi-socket", ## Important - only one process should start "max-procs" => 1, "check-local" => "disable" )) )
CppCMS configuration:
{ "service" : { "api" : "fastcgi", "socket" : "/tmp/hello-fastcgi-socket" } }
Make sure lighttpd has sufficient access rights to read and write to socket '/tmp/hello-fastcgi-socket'.
If you want to use TCP/IP rather then Unix sockets, replace
- In lighttpd configuration:
"socket" => "/tmp/hello-fastcgi-socket",
by"host" => "127.0.0.1", "port" => 8081,
- In cppcms configuration:
"socket" : "/tmp/hello-fastcgi-socket"
, by"ip": "127.0.0.1" , "port" : 8081,
If you have further trouble check the log '/var/log/lighttpd/error.log'
Lighttpd, SCGI
Lighttpd, SCGI, Start by Web Server (lighttpd >=1.4.23)
You should enable mod-scgi and then use this Configuration file:
scgi.server = ( ## The script name of the application "/hello" => (( ## Command line to run "bin-path" => "/opt/app/bin/hello -c /opt/app/etc/config.js", "socket" => "/tmp/hello-fcgi-socket", ## Important - only one process should start "max-procs" => 1, "check-local" => "disable" )) )
CppCMS configuration:
{ "service" : { "api" : "scgi", "socket" : "stdin" // use server's socket } }
Lighttpd, SCGI, External Start
You should enable mod-scgi and then use this Configuration file:
scgi.server = ( ## The script name of the application "/hello" => (( "socket" => "/tmp/hello-scgi-socket", ## Important - only one process should start "max-procs" => 1, "check-local" => "disable" )) )
CppCMS configuration:
{ "service" : { "api" : "scgi", "socket" : "/tmp/hello-scgi-socket" // use server's socket } }
If you want to use TCP/IP rather then Unix sockets, replace
- In lighttpd configuration:
"socket" => "/tmp/hello-scgi-socket",
by"host" => "127.0.0.1", "port" => 8081,
- In cppcms configuration:
"socket" : "/tmp/hello-scgi-socket"
, by"ip": "127.0.0.1" , "port" : 8081,
Apache
Apache, FastCGI
You need to enable at least two modules: mod_fastcgi
and mod_alias
For each case we prepare mod_fastcgi
configuration file
and out config.js.
Note: below we present you an example fastcgi.conf configuration. Be aware that these settings will affect your whole web server. If instead you desire to set these to affect only one specific virtual host, you must place the settings in your virtual host's configuration file (e.g. within /etc/apache2/sites-available
on a Debian system). Check the official Apache documentation for details.
Apache, FastCGI, Start by Web Server
Apache configuration:
FastCgiIpcDir /var/lib/apache2/fastcgi # Usually it is given in fastcgi.conf by default FastCgiServer /opt/app/bin/hello -initial-env CPPCMS_CONFIG=/opt/app/etc/config.js -socket /tmp/hello-fcgi-socket # CPPCMS_CONFIG should hold the path to configuration file. # Note: you can't pass command line parameter # so you pass the location of configuration file # via CPPCMS_CONFIG environment variable FastCGIConfig -maxProcesses 1 -processSlack 1 # This is important - we want apache to use only # one process as we have cache and many other # goodies handled by outsefs ScriptAliasMatch ^/hello(.*)$ /opt/app/bin/hello$1 # We map script "/hello" to our application AddHandler fastcgi-script /opt/app/bin/hello
CppCMS configuration:
{ "service" : { "api" : "fastcgi", "socket": "stdin" // we use socket given by server } }
Apache, FastCGI, Independent start
Apache configuration:
FastCgiIpcDir /var/lib/apache2/fastcgi # Usually it is given in fastcgi.conf by default FastCgiExternalServer /opt/app/bin/hello -socket /tmp/hello-fcgi-socket # We provide a socket the application listens on. ScriptAliasMatch ^/hello(.*)$ /opt/app/bin/hello$1 # We map script "/hello" to our application AddHandler fastcgi-script /opt/app/bin/hello
CppCMS configuration:
{ "service" : { "api" : "fastcgi", "socket": "/tmp/hello-fcgi-socket" // Same as in apache config } }
Now you should run the CppCMS application independently
as /opt/app/bin/hello -c /opt/app/etc/config.js
If you want to use TCP/IP sockets and not Unix one change
- in
FastCgiExternalServer
line parameter-socket
to-host 127.0.0.1:8081
- in CppCMS config change
"socket": "/tmp/hello-fcgi-socket"
to"ip" : "127.0.0.1", "port" : 8081
Apache, SCGI
Apache's mod_scgi
supports only in-depended/external start and works over TCP/IP sockets, so the configuration is quite simple:
Apache's module configuration:
SCGIMount /hello 127.0.0.1:8081
We pass the script name as mount point and ip:port as point to connect cppcms application.
CppCMS configuration:
{ "service" : { "api" : "scgi", "ip" : "127.0.0.1", "port" : 8081 } }
Now you should run the CppCMS application independently
as /opt/app/bin/hello -c /opt/app/etc/config.js
and Apache would connect to it.
Nginx
Nginx supports only FastCGI protocol with external application start.
Note: Nginx's SCGI module is broken as it does not confirm SCGI specifications: it requires rather HTTP response then CGI one. It does not generate SCRIPT_NAME
and PATH_INFO
variables at all. Don't use it!
Also Nginx's fastcgi module require manual generation
of SCRIPT_NAME
and PATH_INFO
variables.
Nginx, FastCGI
Web Server Configuration under server
section:
# Specify UTL to match location ~ ^/hello.*$ { # Socket to communicate fastcgi_pass unix:/tmp/hello-fcgi-socket; # Setup value of PATH_INFO variable fastcgi_split_path_info ^(/hello)((?:/.*))?$; fastcgi_param PATH_INFO $fastcgi_path_info; # # You can either use "include fastcgi_params;" # or set the variables below manually # # All supported CGI variables fastcgi_param SCRIPT_NAME /hello; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; 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; 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; # end of server variables }
And the usual CppCMS's config:
{ "service" : { "api" : "fastcgi", "socket" : "/tmp/hello-fcgi-socket" } }
Of course the CppCMS's service should be started independently.
For using TCP/IP protocol replace:
- In nginx's configuration replace the line
fastcgi_pass unix:/tmp/hello-fcgi-socket;
byfastcgi_pass 127.0.0.1:8081;
- In CppCMS's configuration as usual:
"socket" : "/tmp/hello-fcgi-socket"
, by"ip": "127.0.0.1" , "port" : 8081,
Nginx, SCGI
First of all before you try use SCGI I'd recommend to use FastCGI protocol unless you have very good reasons.
Current (1.0.x nginx version) SCGI protocol implementation for Nginx has a bug:
It does not handle CGI headers as expected so CppCMS should create HTTP headers instead of CGI ones.
Thus service.generate_http_headers
option
should be set to true
In development version of nginx >= 1.1.17
this bug
was fixed, so you don't need the option
service.generate_http_headers
any more.
Web Server Configuration under server
section:
location ~ ^/hello(/.*)$ { # Communication protocol scgi_pass unix:/tmp/hello-scgi-socket; scgi_param SCRIPT_NAME /hello; scgi_param PATH_INFO $1; # # You can either use "include scgi_params;" # or set the variables below manually # scgi_param QUERY_STRING $query_string; scgi_param REQUEST_METHOD $request_method; scgi_param CONTENT_TYPE $content_type; scgi_param CONTENT_LENGTH $content_length; scgi_param REQUEST_URI $request_uri; scgi_param DOCUMENT_URI $document_uri; scgi_param DOCUMENT_ROOT $document_root; scgi_param SERVER_PROTOCOL $server_protocol; scgi_param GATEWAY_INTERFACE CGI/1.1; scgi_param SERVER_SOFTWARE nginx; scgi_param REMOTE_ADDR $remote_addr; scgi_param REMOTE_PORT $remote_port; scgi_param SERVER_ADDR $server_addr; scgi_param SERVER_PORT $server_port; scgi_param SERVER_NAME $server_name; # end of scgi_params }
And the special CppCMS's configuration for Nginx.
{ "service" : { "api" : "fastcgi", "socket" : "/tmp/hello-fcgi-socket", // the option below required for nginx < 1.1.17 "generate_http_headers" : true } }
Of course the CppCMS's service should be started independently.
For using TCP/IP protocol replace:
In nginx's configuration replace the line scgi_pass unix:/tmp/hello-fcgi-socket;
by scgi_pass 127.0.0.1:8081;
IIS
Before you try to use IIS in front of CppCMS I'd recommend you to chose another web server that is more friendly to web developers who use web server independent API like FastCGI.
Best Approach
Configure CppCMS with some other good web server like Apache or Nginx and forward requests from IIS to it.
HTTP Connectivity
Is probably the most solid option. Forward all requests relevant to the web application the the CppCMS internal web server - use IIS as reverse proxy.
Note: give IIS the job of serving static files. It would likely do it better then CppCMS internal web server.
FastCGI Connectivity
FastCGI - don't use it, it was designed to run PHP and nothing more.
IIS's FastCGI implementation is broken and does not support multi-threaded FastCGI applications.
It also does not provide an option to configure specific port making it even impossible to use CppCMS application with IIS.
SCGI Connectivity
Using with ISAPI SCGI.
There is SCGI ISAPI extension that allows to use external SCGI applications: isapi_scgi
Note: The limitations described below refer to V0.6 of the extension. Starting with version 0.8, isapi_scgi supports both the CGI style (default) response as well non-parsed headers as in 0.6. It is also possible to configure it to pass additional headers without recompilation. See the documentation at the above link for details.
However it (v0.6) has two big limitations:
It does not support real CGI response from the client and expects HTTP response.
Starting from CppCMS 0.99.10 it is possible to set an option
service.generate_http_headers
totrue
. This option tells CppCMS to generate HTTP rather then CGI response headers.Using this option it was possible to run successfully CppCMS application with IIS.
It supports only predefined set of HTTP headers so if you will need to get custom headers from for example AJAX responses you'll need to alter
isapi_scgi
sources.
In order to configure ISAPI extension follow the instructions on this web site.
The CppCMS configuration should look like this:
{ "service" : { "api" : "scgi", "ip" : "127.0.0.1", "port" : 9999, "generate_http_headers" : true } }
Troubleshooting ISAPI SCGI extension.
Note: again, this section is only relevant for isapi_scgi v0.6, not later versions.
First of all you can get sources for isapi_scgi.dll
at:
http://twapi.cvs.sourceforge.net/viewvc/twapi/isapi/
Just click download GNU Tarball.
There are several reasons to build it on your own:
Currently the project provides only 32 bit builds of this dll, if you need 64 bit or you'll need to build it manually.
If you need support of custom HTTP headers you'll have to add them in scgi.c.
If you want to build it with gcc you need to apply following changes:
--- scgi_old.h 2011-08-17 10:48:32.109547500 +0300 +++ scgi.h 2011-08-17 10:50:26.184022000 +0300 @@ -37,3 +37,3 @@ */ -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__GNUC__) # define COPY_MEMORY(d, s, n) memcpy((d), (s), (n)) @@ -48,3 +48,3 @@ ZLINK_CREATE_TYPEDEFS(context_t); -typedef struct context { +struct context { OVERLAPPED ovl; /* Must be first structure */ @@ -81,3 +81,3 @@ buffer_t buf; /* Data buffer */ -} context_t; +};
And the you'll be able to build the DLL as:
gcc -O2 -shared buffer.c scgi.c logger.c -lws2_32 -o isapi_scgi.dll
Configuring Other Web Servers
When it comes to configuration of the web servers not mentioned above you should consider following points:
If the web server allows you to start the application you should make sure it starts only a single process.
Otherwise you may experience problems with cache invalidation, session management and your asynchronous applications would likely not work as they don't share the same process.
Make sure that the FastCGI or SCGI support confirm to the standard. For example: Nginx's SCGI connectors do not parse
Status
HTTP header and create correct response; IIS's SCGI module does not send HTTP status line at all and expect HTTP like CGI output.Prefer FastCGI protocol if available as implementations of SCGI usually have lower quality.
Under Microsoft Windows platform, named pipes are not supported, only TCP/IP connections should be used.
Note: under Windows named pipes are frequently used as replacement of Unix sockets, they are not supported as they have very different behavior.
Make sure that
SCRIPT_NAME
andPATH_INFO
CGI variables are set correctly. In our case, given URL/hello/you
SCRIPT_NAME
should be/hello
andPATH_INFO
should be/you
Notes for CppCMS 0.0.x users
CppCMS 0.0.x's web server setup is similar to CppCMS 1.x.x one, as both support FastCGI and SCGI protocols, however the configuration file of the 0.0.x version is quite different.
See:
The protocol is specified as "service.api" and allows options "fastcgi" and "scgi".
However the communication is different.
Unix domain socket defined as:
service.socket = "/path/to/socket"
TCP/IP socket defined as
service.socket = "IP:PORT"
Socket taken from standard input - just make sure that
service.socket
is not defined.
For example:
FastCGI, TCP/IP
CppCMS 1.x.x
{ "service" : { "api" : "fastcgi", "ip" : "127.0.0.1", "port" : 6000 } }
CppCMS 0.0.x
service.api = "fastcgi" service.socket = "127.0.0.1:6000"
SCGI, Unix Socket
CppCMS 1.x.x
{ "service" : { "api" : "scgi", "socket" : "/tmp/app.sock", } }
CppCMS 0.0.x
service.api = "scgi" service.socket = "/tmp/app.sock"
FastCGI, standard input (started by web server)
CppCMS 1.x.x
{ "service" : { "api" : "fastcgi", "socket" : "stdin", } }
CppCMS 0.0.x
service.api = "fastcgi" # service.socket - undefined
← Thread Safety | Top | How to run the application at the root of the web server →