NGINX

How to self host a NGINX HTTP server and reverse proxy




Installation

pacman -Syu nginx-mainline certbot certbot-nginx

Configuration

/etc/nginx/nginx.conf
user http;
worker_processes auto;
worker_cpu_affinity auto;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    multi_accept on;
    worker_connections  1024;
}


http {
    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 4096;
    client_max_body_size 32M;

    # Excessive requests within the burst limit will be served immediately regardless of the specified rate,
    # requests above the burst limit will be rejected with the 503 error.
    # limit_req_zone $binary_remote_addr zone=one:20m rate=5r/s;
    # limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    # MIME
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    
    # logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;
    #access_log  logs/access.log  main;
    
    # load configs
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    gzip  on;
    gzip_vary on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "MSIE [1-6]\.";
}


include /etc/nginx/passthrough.conf;

Managing server entries

Put different server blocks in different files.
This allows you to easily enable or disable certain sites.

Server block configuration files

mkdir /etc/nginx/sites-available

Symlinks to enable sites

mkdir /etc/nginx/sites-enabled

Enable HTTP server

systemctl enable nginx

Configure SSL

/etc/letsencrypt/options-ssl-nginx.conf
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;

ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;

Andreas Bauer. All rights reserved.

Website server block

How to setup a server block for your website




Server block configuration

/etc/nginx/sites-available/lnxsrv.org.conf
server {
    listen 443 ssl;
    http2  on;
    
#   listen [::]:443 ssl http2;

    server_name lnxsrv.org;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/lnxsrv.org.error.log;
    access_log  /var/log/nginx/lnxsrv.org.access.log;

    # How long Nginx is waiting between the writes of the client body
    # client_body_timeout 10s;
    # How long Nginx is waiting between the writes of client header
    # client_header_timeout 10s;

        location / {
            root   /srv/http/lnxsrv.org;
            index  index.html index.htm;
	    # limit_req zone=one burst=60 nodelay;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/lnxsrv.org/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/lnxsrv.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;
    
    # Cache-control Directive Header
    #add_header Surrogate-Control "public, no-transform, no-cache, max-age=86400";
    expires 1d;    
    add_header Cache-Control "public, no-transform";

    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Content Security Policy (CSP) Header
    # add_header Content-Security-Policy "default-src 'self';" always;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/lnxsrv.org/chain.pem; # managed by Certbot
    
    # OCSP stapling   
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot
}

server {
    if ($host = lnxsrv.org) {
    return 301 https://$host$request_uri;
    } # managed by Certbot
    listen       80;
#   listen  [::]:80;
    server_name  lnxsrv.org;
    return 404; # managed by Certbot
}

ln -s /etc/nginx/sites-available/lnxsrv.org.conf /etc/nginx/sites-enabled/lnxsrv.org.conf

Check nginx configuration file syntax

nginx -t

Restart service

systemctl restart nginx.service

unlink /etc/nginx/sites-enabled/lnxsrv.org.conf

Andreas Bauer. All rights reserved.

Cozy reverse proxy

How to setup a reverse proxy for Cozy




Server block configuration

/etc/nginx/sites-available/cozy.wildw1ng.com.conf
server {
    listen 443 ssl;
    http2  on;
    
#   listen [::]:443 ssl http2;

    server_name .cozy.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/cozy.wildw1ng.com.error.log;
    access_log  /var/log/nginx/cozy.wildw1ng.com.access.log;

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/wildw1ng.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/wildw1ng.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;
    
    # Limit max upload size
    client_max_body_size 1g;

    location / {
        # IP address of cozy server
	    proxy_pass         http://10.0.1.15:8080;        
        proxy_http_version 1.1;
        proxy_redirect http:// https://;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection connection_upgrade;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;
    
    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/wildw1ng.com/chain.pem; # managed by Certbot

    # OCSP stapling
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot
}

server {
    if ($host = .cozy.wildw1ng.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot
    listen       80;
#   listen  [::]:80;
    server_name *.cozy.wildw1ng.com;
    return 404; # managed by Certbot
}

ln -s /etc/nginx/sites-available/cozy.wildw1ng.com.conf /etc/nginx/sites-enabled/cozy.wildw1ng.com.conf

Check nginx configuration file syntax

nginx -t

Restart service

systemctl restart nginx.service

unlink /etc/nginx/sites-enabled/cozy.wildw1ng.com.conf

Andreas Bauer. All rights reserved.

Guacamole reverse proxy

How to setup a reverse proxy for Guacamole




Server block configuration

/etc/nginx/sites-available/guac.wildw1ng.com.conf
server {
    listen 443 ssl;
    http2  on;
    
#   listen [::]:443 ssl http2;

    server_name guac.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/guac.wildw1ng.com.error.log;
    access_log  /var/log/nginx/guac.wildw1ng.com.access.log;

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/wildw1ng.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/wildw1ng.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;

    location / {
        # IP address of guacamole server
        proxy_pass         http://10.0.1.12:8080/guacamole/;        
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;
    
    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/wildw1ng.com/chain.pem; # managed by Certbot

    # OCSP stapling
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot

}

server {
    if ($host = guac.wildw1ng.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot
    listen       80;
#   listen  [::]:80;
    server_name  guac.wildw1ng.com;
    return 404; # managed by Certbot
}

ln -s /etc/nginx/sites-available/guac.wildw1ng.com.conf /etc/nginx/sites-enabled/guac.wildw1ng.com.conf

Check nginx configuration file syntax

nginx -t

Restart service

systemctl restart nginx.service

unlink /etc/nginx/sites-enabled/guac.wildw1ng.com.conf

Andreas Bauer. All rights reserved.

Plex reverse proxy

How to setup a reverse proxy for Plex




Server block configuration

/etc/nginx/sites-available/plex.wildw1ng.com.conf
server {
    listen 443 ssl;
    http2  on;
    
#   listen [::]:443 ssl http2;

    server_name plex.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/plex.wildw1ng.com.error.log;
    access_log  /var/log/nginx/plex.wildw1ng.com.access.log;

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/wildw1ng.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/wildw1ng.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;

    location / {
        # IP address of Plex Media Server
        proxy_pass http://10.0.1.11:32400;
        proxy_buffering     off;
        proxy_redirect      off;
        proxy_http_version  1.1;
        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    Upgrade         $http_upgrade;
        proxy_set_header    Connection      $http_connection;
        proxy_cookie_path   /web/           /;
        # access_log          off;
	}
        
	error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/wildw1ng.com/chain.pem; # managed by Certbot
    
    # OCSP stapling
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot

}

server {
	if ($host = plex.wildw1ng.com) {
	return 301 https://$host$request_uri;
	} # managed by Certbot
	listen       80;
#   	listen  [::]:80;
	server_name  plex.wildw1ng.com;
	return 404; # managed by Certbot
}

ln -s /etc/nginx/sites-available/plex.wildw1ng.com.conf /etc/nginx/sites-enabled/plex.wildw1ng.com.conf

Check nginx configuration file syntax

nginx -t

Restart service

systemctl restart nginx.service

Configuring the Plex Media Server

Browse to http://localhost:32400/web/

Settings > Network

plex-custom-server-access-url Within the field Custom Server Access URL’s add http://plex.wildw1ng.com:80,https://plex.wildw1ng.com:443

plex-secure-connections Also make sure to change the Secure Connections setting to ‘Preferred’.


unlink /etc/nginx/sites-enabled/plex.wildw1ng.com.conf

Andreas Bauer. All rights reserved.

PostfixAdmin reverse proxy

How to setup a reverse proxy for PostfixAdmin




Prepare server block for certbot

/etc/nginx/sites-available/postfixadmin.wildw1ng.com
server {
    listen 80;

    server_name postfixadmin.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/postfixadmin.wildw1ng.com.error.log;
    access_log  /var/log/nginx/postfixadmin.wildw1ng.com.access.log;

    location / {
            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_pass http://10.0.1.18/postfixadmin/;
    } 

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
}

ln -s /etc/nginx/sites-available/postfixadmin.wildw1ng.com /etc/nginx/sites-enabled/postfixadmin.wildw1ng.com

Get SSL certificates with Certbot via Let’s Encrypt

certbot --nginx --staple-ocsp

Server block configuration

/etc/nginx/sites-available/postfixadmin.wildw1ng.com
erver {
    listen 443 ssl http2;
#   listen [::]:443 ssl http2;

    server_name postfixadmin.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/postfixadmin.wildw1ng.com.error.log;
    access_log  /var/log/nginx/postfixadmin.wildw1ng.com.access.log;

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/postfixadmin.wildw1ng.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/postfixadmin.wildw1ng.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;

    location / {
            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_pass http://10.0.1.18/postfixadmin/;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/postfixadmin.wildw1ng.com/chain.pem; # managed by Certbot

    # OCSP stapling
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 30s;
}

server {
    if ($host = postfixadmin.wildw1ng.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot
    listen       80;
#   listen  [::]:80;
    server_name  postfixadmin.wildw1ng.com;
    return 404; # managed by Certbot
}

Restart service

systemctl restart nginx.service

unlink ln -s /etc/nginx/sites-enabled/plex.wildw1ng.com

Andreas Bauer. All rights reserved.

Virtual Mail Server reverse proxy

How to setup a reverse proxy for Virtual Mail Server




Prepare server block for certbot

/etc/nginx/sites-available/mail.wildw1ng.com
server {
    listen 80;

    server_name mail.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/mail.wildw1ng.com.error.log;
    access_log  /var/log/nginx/mail.wildw1ng.com.access.log;

    location / {
        # IP address of mail server
        proxy_pass         http://10.0.1.18/;
        proxy_set_header X-Real-IP $remote_addr;    
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
}

ln -s /etc/nginx/sites-available/mail.wildw1ng.com /etc/nginx/sites-enabled/mail.wildw1ng.com

Get SSL certificates with Certbot via Let’s Encrypt

certbot --nginx --staple-ocsp

Server block configuration

/etc/nginx/sites-available/mail.wildw1ng.com
server {
    listen 443 ssl http2;

    server_name mail.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/mail.wildw1ng.com.error.log;
    access_log  /var/log/nginx/mail.wildw1ng.com.access.log;

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/mail.wildw1ng.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/mail.wildw1ng.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;

    location / {
        # IP address of mail server
        proxy_pass         http://10.0.1.18/;
        proxy_set_header X-Real-IP $remote_addr;

        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/mail.wildw1ng.com/chain.pem; # managed by Certbot

    # OCSP stapling
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot
}

server {
    if ($host = mail.wildw1ng.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot
    listen       80;
    server_name  mail.wildw1ng.com;
    return 404; # managed by Certbot
}

Restart service

systemctl restart nginx.service

unlink ln -s /etc/nginx/sites-enabled/plex.wildw1ng.com

Andreas Bauer. All rights reserved.

Zabbix reverse proxy

How to setup a reverse proxy for Zabbix




Prepare server block for certbot

/etc/nginx/sites-available/zabbix.wildw1ng.com
server {
    listen 80;

    server_name zabbix.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/zabbix.wildw1ng.com.error.log;
    access_log  /var/log/nginx/zabbix.wildw1ng.com.access.log;

    location / {
        # IP address of Zabbix server
        proxy_pass         http://archlinux-zabbix/zabbix/;
        proxy_http_version 1.1;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_set_header   X-Forwarded-Server $host;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cookie_path /zabbix /;       
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
}

ln -s /etc/nginx/sites-available/zabbix.wildw1ng.com /etc/nginx/sites-enabled/zabbix.wildw1ng.com

Get SSL certificates with Certbot via Let’s Encrypt

certbot --nginx --staple-ocsp

Server block configuration

/etc/nginx/sites-available/zabbix.wildw1ng.com
server {
    listen 443 ssl http2;
#   listen [::]:443 ssl http2;

    server_name zabbix.wildw1ng.com;

    rewrite     https://$host$request_uri?  permanent;

    error_log   /var/log/nginx/zabbix.wildw1ng.com.error.log;
    access_log  /var/log/nginx/zabbix.wildw1ng.com.access.log;

    # These are the paths to your generated Let's Encrypt SSL certificates.
    ssl_certificate /etc/letsencrypt/live/zabbix.wildw1ng.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/zabbix.wildw1ng.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache   shared:SSL:60m;

    location / {
        # IP address of Zabbix server
        proxy_pass         http://archlinux-zabbix/zabbix/;
        proxy_http_version 1.1;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_set_header   X-Forwarded-Server $host;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cookie_path /zabbix /;       
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    
    # Anti-MIME-Sniffing header
    add_header X-Content-Type-Options nosniff;

    # Anti-ClickJacking Header
    add_header  X-Frame-Options "SAMEORIGIN" always;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/letsencrypt/live/zabbix.wildw1ng.com/chain.pem; # managed by Certbot

    # OCSP stapling
    ssl_stapling on; # managed by Certbot
    ssl_stapling_verify on; # managed by Certbot
}

server {
    if ($host = zabbix.wildw1ng.com) {
    return 301 https://$host$request_uri;
    } # managed by Certbot
    listen       80;
#   listen  [::]:80;
    server_name  zabbix.wildw1ng.com;
    return 404; # managed by Certbot
}

Restart service

systemctl restart nginx.service

unlink /etc/nginx/sites-enabled/zabbix.wildw1ng.com