NaviServer - programmable web server
4.99  5.0

[ Main Table Of Contents | Table Of Contents | Keyword Index ]

admin-config(n) 4.99.30 manual "NaviServer Manual"

Name

admin-config - NaviServer Configuration Reference

Table Of Contents

Description

When NaviServer is started, typically a configuration file is provided providing certain settings for the server. The configuration file includes network configuration options, log file information, loading of modules and database drivers and the like. Actually, the configuration file can contain the definition of multiple servers, running concurrently or depending on command line arguments also separately (see admin-maintenance).

The NaviServer configuration file consists of multiple sections containing global configuration of the instance and sections for each server and module. The configuration file is actually a Tcl script, such that at user can set variables, defined procs to avoid repeated patterns and the like. Tcl variables are typically used to certain parameters at the begin of the file, which might be often changed. This eases the maintenance.

The following sample configuration files might be used as a starting point for site specific configurations: Sample documented configuration files:

Several configuration hints and details can be found also on other spaces in the manual, such as e.g. in admin-tuning or for module specific parameters (which might not be necessary in every installation. Furthermore, the configuration mechanism of NaviServer is extensible, therefore, modules and applications can as well use the configuration file with its abstraction to define application specific parameters. So, a listing of the parameters can never complete. In this page, we primarily define introductory examples for typical usage scenarios.

The main sections of a configuration file are:

EXAMPLES

In general, when modifying configuration files, it is always a good idea to check whether a configuration file is syntactically correct before starting the server. This can reduce the downtime of a production server in case of typos. A configuration file named "nsd-config.tcl" can be checked with the command line option -T of NaviServer.

 /usr/local/ns/bin/nsd -t nsd-config.tcl -T

The global parameters contain the basic setup information, where for example the root of the root of nsd is, where the server log is to be written, or whether the server runs behind a proxy server or not.

 ns_section ns/parameters {
   ns_param home             /var/www/myserver/
   ns_param tcllibrary       tcl
   ns_param serverlog        error.log
   # ...
   ns_param reverseproxymode true
 }

When reverse proxy mode is turned on, the server assumes it is running behind a reverse proxy server. In this case, commands referring to the client IP address will return on default the value as provided by the reverse proxy server (i.e. provided via the x-forwarded-for header field). This will effect the results of ns_conn peeraddr and various introspection commands.

Below we address some general design consideration when tailoring your one configuration files. Check for simple or real-live setups of larger installations by the provided sample configuration files.

One of the core components of the configuration file are the network drivers: what protocols should be used, on which addresses/ports should be used, or how to set up virtual servers. The most important network drivers of NaviServer are nssock and nsssl.

Several additional network drivers are available via extra modules, such as e.g. nsudp, nssmtpd (for a full list of modules, see the module repository).

Single Server, single address, single port

In the simplest case, one defines in a configuration file a single server s1 with single network driver nssock. In the example below the server is listening on port 8000.

 ns_section ns/servers {
   ns_param s1 "Server Instance 1"
 }
 
 ns_section ns/server/s1/modules {
   ns_param nssock  nssock.so
 }
 
 ns_section ns/server/s1/module/nssock {
   ns_param address 0.0.0.0
   ns_param port    8000
 }

In this example, the module is loaded for the server "s1". We show in later examples, how to load a network driver globally, such that one network driver can be used for multiple servers.

Multiple alternative servers in one configuration file

It is as well possible to define multiple servers in the same configuration file (here s1 and s2). These servers use the same driver nsock but with different ports. In this case it is sufficient to load the driver once.

 ns_section ns/servers {
   ns_param s1     "Server Instance 1"
   ns_param s2     "Server Instance 1"
 }
 
 #
 # Server s1
 #
 ns_section ns/server/s1/modules {
   ns_param nssock  nssock.so
 }
 
 ns_section ns/server/s1/module/nssock {
   ns_param address  0.0.0.0
   ns_param port     8000
 }
 
 #
 # Server s2
 #
 ns_section ns/server/s2/modules {
   ns_param nssock   nssock.so
 }
 
 ns_section ns/server/s2/module/nssock {
   ns_param address  0.0.0.0
   ns_param port     8001
 }

When the configuration file above is named e.g. two-server-config.tcl, the two servers can be started with a command line like:

 /usr/local/ns/bin/nsd -u nsadmin -t two-server-config.tcl -f

When it is the goal to start only one of these servers, one can use e.g. the following command:

/usr/local/ns/bin/nsd -u nsadmin -t two-server-config.tcl -f -server s2

Single server listening on multiple IP addresses

Often, a server has the requirement to listen on multiple addresses, such as on one (or many) IPv4 and one (or many) IPv6 addresses. This can be addressed by simply providing the list of values as a parameter value.

 ns_section ns/servers {
   ns_param s1 "Server Instance 1"
 }
 
 ns_section ns/server/s1/modules {
   ns_param nssock  nssock.so
 }
 
 ns_section ns/server/s1/module/nssock {
   ns_param address "137.208.116.31 2001:628:404:74::31"
   ns_param port    8000
 }

Single server listening on multiple ports

Similarly, we can define a single server, listening on multiple ports. In this case, one can load multiple instances of the driver where each of the driver listens on a different port. In the following example we name the different instances of the network driver nssock1 and nssock2.

 #
 # Server s1, using listening on two ports
 #
 ns_section ns/server/s1/modules {
   ns_param   nssock   nssock.so
 }
 
 ns_section ns/server/s1/module/nssock {
   ns_param address   0.0.0.0
   ns_param port      "8000 8001"
 }

When multiple IP addresses and multiple ports are specified, the server will be listening for every specified address on every specified port. In the following example, it will listen on four different combinations of addresses and ports.

 ns_section ns/server/s1/module/nssock {
   ns_param address "137.208.116.31 2001:628:404:74::31"
   ns_param port    "8000 8001"
 }

Single server registering on multiple drivers

In the last two examples a single server is listening on different ports and or IP addresses but the configuration of the driver was otherwise identical. In case, different driver parameters are needed it is possible to load the same driver multiple times for the same server with different driver names. In the following example we name the different instances of the network driver nssock1 and nssock2.

 #
 # Server s1, using two drivers for listening on two ports on two
 # different addresses.
 #
 ns_section ns/server/s1/modules {
   ns_param nssock1   nssock.so
   ns_param nssock2   nssock.so
 }
 
 ns_section ns/server/s1/module/nssock1 {
   ns_param address   0.0.0.0
   ns_param port      8000
 }
 
 ns_section ns/server/s1/module/nssock2 {
   ns_param address   127.0.0.1
   ns_param port      8001
 }

It would be as well possible to register multiple addresses for every network driver instance (here "nssock1" and "nssock2"). In general, by loading a network driver multiple times, all the of parameters of the driver modules (here nssock) can be modified per driver instance.

Virtual servers

By using virtual servers, multiple different server configurations can be used while using only a single IP address/port combination. The main different between a virtual server and the case of defining multiple alternative servers above is that the servers are available concurrently. The server determines by the "Host:" header field provided by the client to which server the request should be routed. Using such virtual servers is a common technique, where e.g. for the same IP address, multiple DNS names are registered. According to HTTP/1.1, clients have to send the hostname in the host header field to the server, such that the server can behave differently depending on the contents of this field.

NaviServer can define multiple virtual servers, where each of the servers has a separate setup (e.g., different number of threads defined, different page directories), separate blueprints (e.g., loading of different modules), uses different network drivers, etc. (see Figure 1).

NaviServer Blueprint

Figure 1: NaviServer Blueprint (per server)

When NaviServer is started, it reads first the configuration file, which contains the definition of all servers, and then, it creates and configures the virtual servers based on this information. This is also the reason, why certain (server-specific) commands cannot be contained (and executed) in the configuration file (e.g., registering URL handlers, callbacks, etc.), but can be loaded from the module files (see also tcl-libraries.html). Additionally, it is possible to specify server specific commands in the section ns/server/SERVERNAME/tcl with the parameter initcmds (see also tcl-libraries.html).

Note that it is also possible to define virtual servers with a single NaviServer server definition, but this will be covered later.

In the following example, we define two separate servers "s1" and "s2", which should act as virtual web servers. This means, we want to define one network driver, which listens on a single port, but which should direct requests to one of the two potentially differently configured servers based on the content of the host header field.

Assume for the IP address of the server the DNS names foo.com, bar.com and baz.com are registered. We define server "s1" and "s2" such that "s1" should receive requests from foo.com, and "s2" should receive requests from bar.com and baz.com. Servers "s1" and "s2" have different pagedir definitions.

For defining virtual servers, the network driver has to be loaded globally (i.e., as module ns/module/nssock). For requests with missing/invalid host header fields, we have to define a defaultserver to handle such requests in the global definition. In the section ns/module/nssock/servers we define the mapping between the hostnames and the defined servers.

 #
 # Define two servers s1 and d2 as virtual servers
 #
 ns_section ns/servers {
   ns_param s1  "Virtual Server s1"
   ns_param s2  "Virtual Server s2 "
 }
 ns_section ns/server/s1/fastpath {
   ns_param pagedir /var/www/s1
 }
 ns_section ns/server/s2/fastpath {
   ns_param pagedir /var/www/s2
 }
 
 #
 # Define a global nssock driver,
 # directing requests to the virtual servers
 # based on the "Host:" header field.
 #
 # It is necessary to define a "defaultserver"
 # for requests without a "Host:" header field.
 #
 ns_section ns/modules {
   ns_param nssock nssock.so
 }
 ns_section ns/module/nssock {
   ns_param port          8000
   ns_param defaultserver s1
 }
 
 #
 # Define the mapping between the DNS names and the servers.
 #
 ns_section ns/module/nssock/servers {
   #
   # Domain names for s1
   #
   ns_param s1 foo.com
   #
   # Domain names for s2
   #
   ns_param s2 bar.com
   ns_param s2 baz.com
 }

Note that one can define multiple DNS names also for a single server. With the definition above, "s1" serves foo.com and "s2" serves bar.com and baz.com. Since "s1" is the default server, requests with unregistered hostnames will also be directed to it.

Virtual servers with HTTPS

In general, the logic of the definition of servers and network drivers is the same for HTTP (nssock) and HTTPS (nsssl), except that the latter has some more configuration parameters, such as e.g. the certificate, or a special configuration of the ciphers, etc.

In order to define virtual servers with HTTPS, one can essentially use the definition of the previous section, and load as well the nsssl driver globally, and configure it accordingly.

 #
 # Define a global nsssl driver
 #
 ns_section ns/modules {
   ns_param nssock nsssl.so
 }
 
 ns_section ns/module/nsssl {
   ns_param port          8433
   ns_param defaultserver s1
   ns_param certificate   /usr/local/ns/modules/nsssl/server.pem
 }
 
 ns_section ns/module/nsssl/servers {
   ns_param s1 foo.com
   ns_param s2 bar.com
   ns_param s2 baz.com
 } 

However, this case requires that all accepted hostnames are listed in the certificate. Such certificates are called multi-domain SAN certificates.

However, there might be cases, where a server listening on a single address has to provide different certificates for e.g. "foo.com" and "bar.com". For virtual hosting this is a chicken-egg problem: the right certificate is needed at the time the connection is opened, but the virtual server can be only detected while reading the request header.

This is a well-known problem, for which the SNI TLS extension was invented (a hostname that can be used for identifying the certificate is passed during the TLS handshake as well).

Virtual servers with HTTPS and SNI

In order to configure SNI (Server Name Indication) for HTTPS, one can simply add additional certificates for the server needed. In the following example the default certificate is defined on the level of the global driver (server.pem), whereas the certificate for the server "foo.com" (which will be served by "s1") is defined for the server "s1" separately (foo.com.pem).

 #
 # Define a global nsssl driver
 #
 ns_section ns/modules {
   ns_param nssock nsssl.so
 }
 ns_section ns/module/nsssl {
   ns_param port          8433
   ns_param defaultserver s1
   ns_param certificate   /usr/local/ns/modules/nsssl/server.pem
 }
 ns_section ns/module/nsssl/servers {
   ns_param s1 foo.com
   ns_param s2 bar.com
   ns_param s2 baz.com
 }
 
 #
 # Define a server-specific certificate to enable SNI.
 # Furthermore, activate for server "s1" also OCSP stapling.
 # 
 ns_section ns/server/s1/module/nsssl {
   ns_param certificate   /usr/local/ns/modules/nsssl/foo.com.pem
   ns_param OCSPstapling  on
 }

OCSP (abbreviation of Online Certificate Status Protocol, RFC 2560 and RFC 6066) is a protocol that checks the validity status of a certificate. The term "OCSP stapling" refers to the use of digitally-signed time-stamped OCSP responses in the web server for performance reasons. In the example above, OCSP stapling is defined for server "s1".

Single virtual server with mass virtual hosting (HTTP)

The virtual servers defined in the last sections have the disadvantage that these require to know the server upfront, to include the server definition in the configuration file. Therefore, adding another virtual server requires a restart (which is quick, but still, will interrupt services). In case, the virtual hosts are very similar, it is possible to define a single virtual server hosting multiple domains, serving e.g. from different page directories.

The following example defines server "s1" serving only for HTTP connections over port 8000. The new part is the registration of a callback via ns_serverrootproc, which determines the root directory for serving pages based on the "host" header field. The definition assumes a directory structure like the following, where "foo.com" has, e.g., a different index.html file.

 /var/www/
 ├── default
 │   └── index.html
 ├── foo.com
 │   └── index.html
...

When the content of the host header field (not including the port) is found in the filesystem under /var/www, it is used as the pageroot for this request. It is certainly possible, the extend the example and include the port as well in the directory name.

 #
 # Define server "s1"
 #  - listening on all IP addresses,
 #  - port 8000,
 #  - serve pages from /var/www/
 #
 ns_section ns/servers {
   ns_param s1        "Sample Server"
 }
 ns_section ns/server/s1/modules {
   ns_param nssock    nssock
 }
 ns_section ns/server/s1/module/nssock {
   ns_param address   0.0.0.0
   ns_param port      8000
 }
 ns_section ns/server/s1/fastpath {
   ns_param pagedir   ""
   ns_param serverdir /var/www
 }
 
 #
 # Register for this server a callback for determining the server root
 # depending on the contents of the "host" header field.
 #
 ns_section ns/server/s1/tcl {
   ns_param initcmds {
     ns_serverrootproc {
       set rootDir [ns_server serverdir]
       set dir default
       if {[ns_conn isconnected]} {
         set rawHost [ns_set iget [ns_conn headers] host]
         if {$rawHost ne ""} {
           set hostDict [ns_parsehostport $rawHost]
           if {[::file isdirectory $rootDir/[dict get $hostDict host]]} {
             set dir [dict get $hostDict host]
           } else {
             ns_log debug "... $rootDir/[dict get $hostDict host] does not exist, use default"
           }
         }
       }
       set rootDir $rootDir/$dir
       ns_log debug "... final rootdir '$rootDir'"
       return $rootDir
     }
   }
 }

This approach has the advantage that at runtime of NaviServer, new directories might be added or removed to server additional domains.

Single virtual server with mass virtual hosting using HTTPS and SNI

While the previous section works for plain HTTP, the usage of HTTPS requires SNI and multiple certificates. This feature will be available in NaviServer 5.

More to come here...

See Also

tcl-libraries, tcl-overview

Keywords

OCSP, SNI, SO_REUSEPORT, TCP, TCP_FASTOPEN, configuration, connection thread pools, driver, initcmds, letsencrypt, module, nssock, nsssl, pagedir, performance, prebind, redirect, reverseproxy, tuning