Configure with Nginx

Load balance Pritunl web server with Nginx

SELinux Configuration

If Nginx is running on a RHEL distributions such as Oracle Linux 8 by default SELinux will prevent proxied web requests from reaching internal servers. This can be enabled by running the commands below.

sudo setsebool -P httpd_can_network_relay 1
sudo setsebool -P httpd_can_network_connect 1

Automatic Updates

The commands below will enable automatic updates on Oracle Linux 8 or any RHEL8 distribution.

sudo dnf -y update
sudo dnf -y install dnf-automatic
sudo sed -i 's/^upgrade_type =.*/upgrade_type = default/g' /etc/dnf/automatic.conf
sudo sed -i 's/^download_updates =.*/download_updates = yes/g' /etc/dnf/automatic.conf
sudo sed -i 's/^apply_updates =.*/apply_updates = yes/g' /etc/dnf/automatic.conf
sudo systemctl enable --now dnf-automatic.timer

Nginx Configuration

The first command below will generate a self signed certificate to handle income requests for unknown domains and return 404. Any certificate information can be provided when prompted from the command.

The next command will write a basic optimized Nginx configuration.

sudo openssl req -x509 -nodes -days 18250 -newkey rsa:4096 -keyout /etc/nginx/ssl/notfound.key -out /etc/nginx/ssl/notfound.crt

sudo tee /etc/nginx/nginx.conf << EOF
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
pcre_jit on;

events {
    worker_connections 2048;
    multi_accept on;
    use epoll;
}

http {
    server_tokens off;
    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    access_log off;
    client_header_timeout 45;
    client_body_timeout 45;
    keepalive_timeout 65;
    connection_pool_size 1024;
    request_pool_size 8k;
    client_header_buffer_size 2k;
    client_body_buffer_size 32k;
    server_names_hash_bucket_size 512;
    server_names_hash_max_size 1024;
    types_hash_max_size 2048;

    server {
        listen 80;
        listen [::]:80;
        server_name _;
        return 404;
    }

    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        ssl_certificate /etc/nginx/ssl/notfound.crt;
        ssl_certificate_key /etc/nginx/ssl/notfound.key;
        server_name _;
        return 404;
    }

    include /etc/nginx/conf.d/*.conf;
}
EOF

Pritunl Server with Certbot

Nginx can also be configured to automatically renew SSL certificates with LetsEncrypt. Replace 10.123.123.123 with the internal IP address of the Pritunl server. Then replace [email protected] and EXAMPLE.DOMAIN.COM with a lowercase email and domain for the Pritunl server. Additional lines can be added to the upstream section to load balance multiple hosts.

The first command below will copy the notfound certificate to the Pritunl server domain. This will allow Nginx to start running initially. The LetsEncrypt certbot will then overwrite this certificate.

sudo cp /etc/nginx/ssl/notfound.crt /etc/nginx/ssl/EXAMPLE.DOMAIN.COM.crt
sudo cp /etc/nginx/ssl/notfound.key /etc/nginx/ssl/EXAMPLE.DOMAIN.COM.key

This configuration will send port 80 requests to /.well-known to the path /usr/share/nginx/html/.well-known where the LetsEncrypt certbot will store verification requests. All other requests will be sent to the Pritunl server.

sudo tee /etc/nginx/conf.d/pritunl-vpn.conf << EOF
upstream pritunl-vpn {
    server 10.123.123.123:443;
}

server {
    listen 80;
    listen [::]:80;
    root /usr/share/nginx/html;
    server_name EXAMPLE.DOMAIN.COM;
    location /.well-known {
      allow all;
    }
    location / {
      return 301 https://EXAMPLE.DOMAIN.COM\$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/nginx/ssl/EXAMPLE.DOMAIN.COM.crt;
    ssl_certificate_key /etc/nginx/ssl/EXAMPLE.DOMAIN.COM.key;
    server_name EXAMPLE.DOMAIN.COM;
    location / {
        proxy_pass https://pritunl-vpn;
        proxy_ssl_verify off;
        proxy_set_header Host \$http_host;
        proxy_set_header X-Forwarded-For \$remote_addr;
    }
}
EOF

This configuration below will only allow access to the /link/state to accept requests from pritunl-link clients. This configuration can be used if the Pritunl server is only being used to accept pritunl-link clients.

sudo tee /etc/nginx/conf.d/pritunl-vpn.conf << EOF
upstream pritunl-vpn {
    server 10.123.123.123:443;
}

server {
    listen 80;
    listen [::]:80;
    root /usr/share/nginx/html;
    server_name EXAMPLE.DOMAIN.COM;
    location /.well-known {
      allow all;
    }
    location / {
      return 404;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    ssl_certificate /etc/nginx/ssl/EXAMPLE.DOMAIN.COM.crt;
    ssl_certificate_key /etc/nginx/ssl/EXAMPLE.DOMAIN.COM.key;
    server_name EXAMPLE.DOMAIN.COM;
    location /link/state {
        proxy_pass https://pritunl-vpn;
        proxy_ssl_verify off;
        proxy_set_header Host \$http_host;
        proxy_set_header X-Forwarded-For \$remote_addr;
    }
    location / {
      return 404;
    }
}
EOF

The scripts below will automatically check for a LetsEncrypt renewal every day.

sudo tee /etc/systemd/system/certbot.target << EOF
[Unit]
Description=Cerbot target
StopWhenUnneeded=yes
EOF

sudo tee /etc/systemd/system/certbot.timer << EOF
[Unit]
Description=Cerbot timer

[Timer]
OnCalendar=*-*-* 8:00:00
Unit=certbot.target

[Install]
WantedBy=basic.target
EOF

sudo tee /etc/systemd/system/certbot.service << EOF
[Unit]
Description=Cerbot
Wants=certbot.timer

[Service]
ExecStart=/usr/bin/certbot-nginx

[Install]
WantedBy=certbot.target
EOF

sudo tee /usr/bin/certbot-nginx << EOF
#!/bin/bash

getcert () {
  echo "Getting certificate email=\$1 domain=\$2"
  /usr/bin/certbot --webroot --agree-tos --non-interactive --webroot-path /usr/share/nginx/html --preferred-challenges http --email \$1 -d \$2 certonly
  /usr/bin/cp -f /etc/letsencrypt/live/\$2/fullchain.pem /etc/nginx/ssl/\$2.crt
  /usr/bin/chown nginx:nginx /etc/nginx/ssl/\$2.crt
  /usr/bin/cp -f /etc/letsencrypt/live/\$2/privkey.pem /etc/nginx/ssl/\$2.key
  /usr/bin/chown nginx:nginx /etc/nginx/ssl/\$2.key
}

getcert "[email protected]" "EXAMPLE.DOMAIN.COM"

/usr/bin/chown -R nginx:nginx /etc/nginx/ssl
/usr/bin/chmod 600 /etc/nginx/ssl/*
/usr/sbin/restorecon -R -v /etc/nginx
/usr/bin/systemctl reload nginx
EOF
sudo chmod +x /usr/bin/certbot-nginx

sudo systemctl daemon-reload
sudo systemctl enable certbot.service
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

sudo systemctl list-timers

Once done start Nginx and update DNS records then obtain the first LetsEncrypt certificate.

sudo systemctl restart nginx
sudo systemctl enable nginx
sudo /usr/bin/certbot-nginx

Pritunl Sync Address

After configuring Pritunl on an Nginx server the Sync Address option in the Pritunl host settings should be configured to the domain for the Nginx server.

327