User Tools

Site Tools


Nginx webserver

Nginx is a high-performance HTTP/S server with other functions as well. It is a perfect candidate to run on OpenWrt due to the performance and memory handling. NB: At this time (2020-07-21), the configuration described below is contained in the master, but not in the current release (19.07).


We can install Nginx with SSL (using libopenssl) by:

 opkg update && opkg install nginx-ssl 

Of course there will be port issues if we installed LuCI before or after Nginx, since the standard LuCI package installs uHTTPd, which also wants to claim port 80 (and port 443 for HTTPS). So configuring and/or portforwarding may be neccessary. There are ways to run LuCI with Nginx but that is not coverd here. For a quick fix, just change the uhttpd port to something else in /etc/config/uhttpd.


The official Documentation contains a Admin Guide. Here we will look at some often used configuration parts and how we handle them at OpenWrt. At different places there are references to the official Technical Specs for further reading.

tl;dr: The main configuration is a minimal configuration enabling the /etc/nginx/conf.d/ directory:

  • There is a _lan.conf containing a default server for the LAN, which includes all *.locations.
  • We can disable parts of the configuration by renaming them.
  • If we want to install other HTTPS servers that are also reachable locally, we can include the /var/lib/nginx/lan_ssl.listen file.
  • We have a server in _redirect2ssl.conf that redirects inexistent URLs to HTTPS, too.
  • We can create a self-signed certificate and add corresponding directives to e.g. by invoking
    nginx-util add_ssl


We modify the configuration by creating different configuration files in the /etc/nginx/conf.d/ directory. The configuration files use the file extensions .locations and .conf plus .crt and .key for SSL certificates and keys. We can disable single configuration parts by giving them another extension, e.g., by adding .disabled. For the new configuration to take effect, we must reload it by:

service nginx reload

For OpenWrt we use a special initial configuration, which is explained below in the section OpenWrt’s Defaults. So, we can make a site available at a specific URL in the LAN by creating a .locations file in the directory /etc/nginx/conf.d/. Such a file consists just of some location blocks. Under the latter link, you can find also the official documentation for all available directives of the HTTP core of Nginx. Look for location in the Context list.

The following example provides a simple template, see at the end for different Locations for Apps and look for other packages using a .locations file, too:

location /ex/am/ple {
        access_log off; # default: not logging accesses.
        # access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout).
        # error_log stderr; # default: logging to logd (init forwards stderr).
        error_log /dev/null; # disable error logging after config file is read.
        # (state path of a file for access_log/error_log to the file instead.)
        index index.html;
# location /eg/static { … }

All location blocks in all .locations files must use different URLs, since they are all included in the _lan.conf that is part of the OpenWrt’s Defaults. We reserve the location / for making LuCI available under the root URL, e.g. All other sites shouldn’t use the root location / without suffix. We can make other sites available on the root URL of other domain names, e.g. on In order to do that, we create a .conf file for every domain name: see the next section New Server Parts. We can also activate SSL there, as described below in the section SSL Server Parts. We use such server parts also for publishing sites to the internet (WAN) instead of making them available just in the LAN.

Via .conf files we can also add directives to the http part of the configuration. The difference to editing the main /etc/nginx/nginx.conf file instead is the following: If the package’s nginx.conf file is updated it will only be installed if the old file has not been changed.

New Server Parts

For making the router reachable from the WAN at a registered domain name, it is not enough to give the name server the internet IP address of the router (maybe updated automatically by a DDNS Client). We also need to set up virtual hosting for this domain name by creating an appropriate server part in a /etc/nginx/conf.d/*.conf file. All such files are included at the start of Nginx by the default main configuration of OpenWrt /etc/nginx/nginx.conf as depicted in OpenWrt’s Defaults.

In the server part, we state the domain as server_name. The link points to the same document as for the location blocks in the Basic Configuration: the official documentation for all available directives of the HTTP core of Nginx. This time look for server in the Context list, too. The server part should also contain similar location blocks as before. We can re-include a .locations file that is included in the server part for the LAN by default. Then the site is reachable under the same path at both domains, e.g., by as well as by

The following example is a simple template:

server {
        listen 80;
        listen [::]:80;
        # location / { … } # root location for this server.
        include '/etc/nginx/conf.d/';

SSL Server Parts

We can enable HTTPS for a domain if Nginx is installed with SSL support. We need a SSL certificate as well as its key and add them by the directives ssl_certificate respective ssl_certificate_key to the server part of the domain. The rest of the configuration is similar as described in the previous section New Server Parts, we only have to adjust the listen directives by adding the ssl parameter, see the official documentation for configuring HTTPS servers, too.

The OpenWrt’s Defaults include a _lan.conf file containing a server part that listens on the LAN address(es) and acts as default_server with ssl on port 443. For making the domain name accessible in the LAN, too, the corresponding server part must listen explicitly on the local IP address(es), cf. the official documentation on request_processing. We can include the file /var/lib/nginx/lan_ssl.listen that contains the listen directives with ssl parameter for all LAN addresses on the HTTP port 443 and is updated automatically.

The official documentation of the SSL module contains an example, which includes some optimizations. The following template is extended similarly:

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        include '/var/lib/nginx/lan_ssl.listen';
        ssl_certificate '/etc/nginx/conf.d/';
        ssl_certificate_key '/etc/nginx/conf.d/';
        ssl_session_cache shared:SSL:32k;
        ssl_session_timeout 64m;
        # location / { … } # root location for this server.
        include '/etc/nginx/conf.d/';

For creating a certificate (and its key) we can use Let’s Encrypt by installing ACME Shell Script:

opkg update && opkg install acme # and for LuCI: luci-app-acme

For the LAN server in the _lan.conf file, the init script /etc/init.d/nginx script installs automatically a self-signed certificate. We can use this mechanism also for other sites by issuing, e.g.:

nginx-util add_ssl
  1. It adds SSL directives to the server part of /etc/nginx/conf.d/ like in the example above.
  2. Then, it checks if there is a certificate and key for the given domain name that is valid for at least 13 months or tries to create a self-signed one.
  3. When cron is activated, it installs a cron job for renewing the self-signed certificate every year if needed, too. We can activate cron by:
    service cron enable && service cron start

Beside the _lan.conf file, the OpenWrt’s Defaults include also the _redirect2ssl.conf file containing a server part that redirects all HTTP request for inexistent URIs to HTTPS.

OpenWrt’s Defaults

The default main configuration file is:

# Please consider creating files in /etc/nginx/conf.d/ instead of editing this.
# For details see
worker_processes auto;
user root;
events {}
http {
        access_log off;
        log_format openwrt
                '$request_method $scheme://$host$request_uri => $status'
                ' (${body_bytes_sent}B in ${request_time}s) <- $http_referer';
        include mime.types;
        default_type application/octet-stream;
        sendfile on;
        client_max_body_size 128M;
        large_client_header_buffers 2 1k;
        gzip on;
        gzip_vary on;
        gzip_proxied any;
        root /www;
        include conf.d/*.conf;

We can pretend the main configuration contains also the following presets, since Nginx is configured with them:

pid "/var/run/";
lock_file "/var/lock/nginx.lock";
error_log "stderr";
proxy_temp_path "/var/lib/nginx/proxy";
client_body_temp_path "/var/lib/nginx/body";
fastcgi_temp_path "/var/lib/nginx/fastcgi";

So, the access log is turned off by default and we can look at the error log by logread, as Nginx’s init file forwards stderr and stdout to the logd. We can set the error_log and access_log to files where the log messages are forwarded to instead (after the configuration is read). And for redirecting the access log of a server or location to the logd, too, we insert the following directive in the corresponding block:

        access_log /proc/self/fd/1 openwrt;

At the end, the main configuration pulls in all .conf files from the directory /etc/nginx/conf.d/ into the http block, especially the following server part for the LAN:

# default_server for the LAN addresses getting the IPs by:
# ifstatus lan | jsonfilter -e '@["ipv4-address","ipv6-address"].*.address'
server {
        server_name _lan;
        include '/var/lib/nginx/lan_ssl.listen.default';
        ssl_certificate '/etc/nginx/conf.d/_lan.crt';
        ssl_certificate_key '/etc/nginx/conf.d/_lan.key';
        ssl_session_cache 'shared:SSL:32k';
        ssl_session_timeout '64m';
        # access_log /proc/self/fd/1 openwrt; # use logd (init forwards stdout).
        include conf.d/*.locations;

It pulls in all .locations files from the directory /etc/nginx/conf.d/. We can install the location parts of different sites there (see above in the Basic Configuration) and re-include them in server parts of other /etc/nginx/conf.d/*.conf files. This is needed especially for making them available to the WAN as described above in the section New Server Parts. All .locations become available on the LAN through the file lan_ssl.listen.default, which contains one of the following directives for every local IP address:

        listen IPv4:443 ssl default_server;
        listen [IPv6]:443 ssl default_server;

The /var/lib/nginx/lan_ssl.listen file contains the same directives without the parameter default_server. We can include this file in other server parts that should be reachable in the LAN through their server_name. Both files /var/lib/nginx/lan_ssl.listen{,.default} are (re-)created if Nginx starts through its init for OpenWrt or the LAN interface changes.

There is also the following server part that redirects requests for an inexistent server_name from HTTP to HTTPS (using an invalid name, more in the official documentation on request_processing):

# acts as default server if there is no other.
server {
        listen 80;
        listen [::]:80;
        server_name _redirect2ssl;
        return 302 https://$host$request_uri;

Nginx’s init file for OpenWrt installs automatically a self-signed certificate for the LAN server part if needed and possible:

  1. Everytime Nginx starts, we check if the LAN is set up for SSL.
  2. We add ssl* directives (like in the example of the previous section SSL Server Parts) to the configuration file /etc/nginx/conf.d/_lan.conf if needed and if it looks “normal”, i.e., it has a server_name _lan; part.
  3. If there is no corresponding certificate that is valid for more than 13 months at /etc/nginx/conf.d/_lan.{crt,key}, we create a self-signed one.
  4. We activate SSL by including the ssl listen directives from /var/lib/nginx/lan_ssl.listen.default and it becomes available by the default redirect from listen *:80; in /etc/nginx/conf.d/_redirect2ssl.conf
  5. If cron is available, i.e., its status is not inactive, we use it to check the certificate for validity once a year and renew it if there are only about 13 months of the more than 3 years life time left.

The points 2, 3 and 5 can be used for other domains, too: As described in the section New Server Parts above, we create a server part in /etc/nginx/conf.d/ with a corresponding server_name; directive and call

nginx-util add_ssl

Locations for Apps

For an overview see the official Admin Guide of Nginx on Reverse Proxy. For logging look at the example in the Basic Configuration, too. Remember to restart Nginx after changing its configuration by:

service nginx reload

PHP with FastCGI

Install PHP using FastCGI:

 opkg update && opkg install php7-fastcgi

In the Nginx configuration we can include the file fastcgi_params, which is installed by default. We create a .location file like the following, see other packages using fastcgi_pass and Nginx's Wiki has a PHP FastCGI Example, too:

location ~ [^/]\.php$ {
    #error_log /dev/null;
    fastcgi_connect_timeout 300s;
    fastcgi_read_timeout 300s;
    fastcgi_send_timeout 300s;
    fastcgi_buffer_size 32k;
    fastcgi_buffers 4 32k;
    fastcgi_busy_buffers_size 32k;
    fastcgi_temp_file_write_size 32k;
    client_header_timeout 10s;
    client_body_timeout 10s;
    send_timeout 60s; # default, increase if experiencing a lot of timeouts.
    output_buffers 1 32k;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param HTTP_PROXY ""; # Mitigate vulnerability.
    if (-f ) {
            # Only throw it at PHP-FPM if file exists (prevents PHP exploits).
            fastcgi_pass;  # or: unix:/var/run/php-fpm.sock;
cgi.force_redirect = 1
cgi.redirect_status_env = "yes";


Install uWSGI and needed plugins:

opkg update && opkg install uwsgi # and the plugin(s) used. 

In the Nginx configuration we can include the file uwsgi_params, which is installed by default. We create a .location file like the following, see also other packages using uwsgi_pass and the uWSGI documentation for Nginx, too:

location /mysite {
    # error_log /dev/null;
    include  /etc/nginx/uwsgi_params;
    uwsgi_pass unix:///var/run/mysite.socket;
    # for CGI (like in LuCI):
    # uwsgi_param SERVER_ADDR $server_addr;
    # uwsgi_modifier1 9;

For uWSGI, we create a configuration handling the application like the following, see other packages using uWSGI, too:

strict = true
; adjust the needed plugins, path, name, user and socket for the application:
plugin = 
chdir = /path/to/app
mount = /mysite=app
; or use cgi = /mysite=/path/or/executable
uid = user
gid = nogroup
chmod-socket = 660
chown-socket = user:nogroup
; Nginx runs as nouser:nogroup
if-not-env = UWSGI_EMPEROR_FD
socket = /var/run/mysite.socket
vacuum = true
; cheap = true
end-if =
disable-logging = true
log-format=%(method) %(uri) => return %(status) (%(rsize) bytes in %(msecs) ms)
manage-script-name = true
thunder-lock = true
enable-threads = true
threads = 3
master = true
; processes = 3
; cheaper-algo = spare
; cheaper = 1
; cheaper-initial = 1
; cheaper-step = 1
; lazy-apps = true
; harakiri = 60
; idle = 360
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
docs/guide-user/services/webserver/nginx.txt · Last modified: 2020/07/29 21:57 by peter-stadler