HOW-TO: Set up NGINX to reverse proxy your jails w/ Certbot

SeaFox

Explorer
Joined
Aug 6, 2013
Messages
98
All right. I tried to follow this guide, and while I had some hiccups on the initial jail and install bit, I am at this point very close to getting this working.

Right now:
  1. I get the "Welcome to nginx!" test page when I go to https://me.ddns.tld, with the green lock icon and all.
  2. I'm getting an A+ security rating with no special futzing around (!).
  3. But I can't access the actual services I have set up. :(

I'm only setting up forwards for two servers right now: Transmission on a separate machine, and my Airsonic jail on the NAS.
Both can be currently reached at http://me.ddns.tld:portnumber.

When I go to https://me.ddns.tld/transmission, I do get prompted for my login for the transmission web interface, but when I log in I get this code 409 page.


When I go to https://me.ddns.tld/airsonic, I actually get the login page for my Airsonic web interface. It looks like it's working fine, but after I log in I get taken to a screen with the background color and that's it. The interface itself never loads.

Here is my nginx.conf:
Code:
#user  nobody;
worker_processes  1;

# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info.
#
#error_log  /var/log/nginx/error.log;
#

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    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"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       443 ssl;
        server_name  me.ddns.tld;
        include ssl_common.conf;
        include proxy_setup.conf;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   /usr/local/www/nginx;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}



And my proxy_setup.conf:
Code:
location /transmission {
proxy_pass http://192.168.9.231:9091/transmission/web;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location /airsonic {
proxy_pass http://192.168.9.226:4040/airsonic;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}



Edit: Okay. I figured out the Transmission issue. I'm required to go through the base IP itself first. The error was because I was trying to redirect right into /transmission/web. Shortening the proxy_pass address to just the base ip:port fixed that. Still stuck on Airsonic, though. Shortening its proxy_pass address did not change things (although it did take longer for the login page to come up).
 
Last edited:

lixenstrand

Cadet
Joined
Aug 9, 2018
Messages
5
Is it possible to hide the ip adress, so that when you test ssl labs it doesn't come up which ip origin the webbserver has?
 

SeaFox

Explorer
Joined
Aug 6, 2013
Messages
98
Is it possible to hide the IP address, so that when you test ssl labs it doesn't come up which IP origin the webbserver has?

That's kinda not how the internet works. If you send a request to a server it has to know what your IP address is to send the response back. You could put a VPN on the jail you're using for the reverse proxy, but that would cause problems with this since the SSL Labs site is going to be trying to communicate with the jail on port 80/443, and you wouldn't be able to get those specific port forwarded on the VPN (without maybe getting a dedicated static IP on the VPN).
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
Just wanted to share since I had a hell of a time getting things to work in Organizr using this tutorial. I had to edit the following line in ssl_common.conf to
Code:
#add_header X-Frame-Options DENY;


I would get blank pages when trying to load tabs without commenting this line.

If you want Organizr as your homepage on your domain edit the http location section of nginx.conf
Code:
        location / {
#Use your Organizr jail IP for the proxy pass
             proxy_pass http://172.16.1.240;
         proxy_redirect off;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     }
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
To get Plex working in Organizr, you need to modify the plex section in proxy_setup.conf. I used the guide here: https://docs.organizr.app/books/setup-features/page/sso#bkmrk-plex

Code:
       location /plex/ {
               proxy_pass http://172.16.1.250:32400/;
               include /usr/local/etc/nginx/proxy.conf;
        }
        if ($http_referer ~ /plex/) {
        rewrite ^/web/(.*) /plex/web/$1? redirect;
        }


Contents of proxy.conf

Code:
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_bind $server_addr;
proxy_buffers 32 4k;
#Timeout if the real server is deadproxy_next_upstream error timeout invalid_header http_500
http_502 http_503;
# Advanced Proxy Config


Maybe there's other ways to get it to work but this made it easier for me and solved my issue of getting a 401 error.

Reverse proxy is working where I can go to mydomain.com/sonarr, for example and all of Organizr works.
 
Last edited:

thatcherk1

Cadet
Joined
May 15, 2019
Messages
9
Hello,
I'm trying to get the auto renew to work. but when I edit the crontab in nano and try and save it I get this:
Code:
crontab: installing new crontab
"/tmp/crontab.sGyl1QxkDm":1: bad minute
crontab: errors in crontab file, can't install


I'm copying and pasting what is in the guide:
Code:
30 1 * * 1 ./certbot/letsencrypt-auto renew --pre-hook "service nginx stop" --post-hook "service nginx start"


Anyone else having this issue?
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
Did something break? I'm having to set this up on a new system and getting this when I run ./letsencrypt-auto --debug certonly --standalone -d myservername.com


Creating virtual environment...
Traceback (most recent call last):
File "<stdin>", line 27, in <module>
File "<stdin>", line 19, in create_venv
File "/usr/local/lib/python2.7/subprocess.py", line 185, in check_call
retcode = call(*popenargs, **kwargs)
File "/usr/local/lib/python2.7/subprocess.py", line 172, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/local/lib/python2.7/subprocess.py", line 394, in __init__
errread, errwrite)
File "/usr/local/lib/python2.7/subprocess.py", line 1047, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
I'm still stumped on this. I'm assuming some dependency for python2.7 are broken. If anyone is able to get this or a newer version that does not rely on python 2.7, please comment so I can get a system up and running!

I looked at Caddy but the one guide I saw wasn't exactly user friendly and in detail.
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
The included letsencrypt method here is outdated and no longer works. Followed instructions here: https://certbot.eff.org/lets-encrypt/freebsd-nginx

Code:
pkg install py36-certbot

certbot certonly --standalone -d yourdomain.com


The rest of the instructions still work. You may need to manually create directories to follow along with instructions here so files go in the same spots. I'll post my nginx.conf and proxy_setup.conf if needed. Basically the same but modified as my previous posts above.
 

Lee Spangler

Dabbler
Joined
Sep 30, 2014
Messages
26
@AirborneTrooper - with the differing directories - what is the cronjob entry?
This won't work - "30 1 * * 1 ./certbot/letsencrypt-auto renew --pre-hook "service nginx stop" --post-hook "service nginx start"
for the same reason the script would not work in the firstplace, right?
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
@AirborneTrooper - with the differing directories - what is the cronjob entry?
This won't work - "30 1 * * 1 ./certbot/letsencrypt-auto renew --pre-hook "service nginx stop" --post-hook "service nginx start"
for the same reason the script would not work in the firstplace, right?

I'm honestly not 100% sure because I really don't know cronjobs well but maybe it's just:
Code:
30 1 * * 1 certbot renew --pre-hook "service nginx stop" --post-hook "service nginx start"


If you run
Code:
certbot renew --pre-hook "service nginx stop" --post-hook "service nginx start"
by itself, it works. I'm not due for an update until October so I won't be able to run it completely until September some time.
 

bermau

Dabbler
Joined
Jul 4, 2017
Messages
28
Hey there,

I followed the guide, and it seems to work pretty well. Kind of. Almost.
I am trying to access my Nextcloud server, and I get the NC UI, the certificate seems ok, but no shares.
Could you try and help me figuring out what´s wrong?

First, on my nginx proxy, here´s some config:
nginx.conf:
Code:
#user  nobody;
worker_processes  1;

# This default error log path is compiled-in to make sure configuration parsing
# errors are logged somewhere, especially during unattended boot when stderr
# isn't normally logged anywhere. This path will be touched on every nginx
# start regardless of error log location configured here. See
# https://trac.nginx.org/nginx/ticket/147 for more info.
#
#error_log  /var/log/nginx/error.log;
#

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    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"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   /usr/local/www/nginx;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    server {
        listen       443 ssl;
        server_name  proxy.domain.com;
        include ssl_common.conf;
        include proxy_setup.conf;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    }

}


proxy_setup.conf
Code:
location /cloud {
        proxy_pass https://192.168.1.235:443/; #(192.168.1.235 being LAN IP of NC server)
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}


ssl_common.conf
Code:
# Thanks to https://cipherli.st/ for providing a great reference! Please check out their site
# to make sure your SSL Configuration is up to date with current standards! Be aware that in this
# example we use a slightly liberal cipherlist to allow for older browsers on older devices, Eg.
# IE8, android 2.4, etc
# Enable Perfect Forward Secrecy (PFS)
ssl_prefer_server_ciphers on;
ssl_certificate /usr/local/etc/letsencrypt/live/proxy.domain.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/proxy.domain.com/privkey.pem;
# Disable SSLv2 and SSLv3 (BEAST and POODLE attacks)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Enable our strong DH Key
ssl_dhparam /usr/local/etc/ssl/dhparams.pem;
# Cipher-list for PFS.
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-G$
ssl_ecdh_curve secp384r1;
# Requires nginx >= 1.1.0
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# Requires nginx >= 1.5.9
ssl_stapling on;
# Requires nginx >= 1.3.7
ssl_stapling_verify on;
# Requires nginx => 1.3.7
resolver 8.8.8.8 4.4.4.4 valid=300s;
resolver_timeout 5s;
# HSTS Support
add_header Strict-Transport-Security "max-age=63072000;includeSubdomains; preload";
# These headers can break applications, be careful!
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;


Then in config.php on Nextcloud I added:

Code:
'overwrite.cli.url' => 'https://proxy.domain.com/cloud/',
'overwritewebroot' => '/cloud',


and proxy.domain.com as trusted domain.
hi,
I have the same problem with my nextcloud, I can access to NC but no data (this directory is unavailable, please check the logs or contact system administrator).
Do you fixed that issue?
nc_error.jpg
 

appliance

Explorer
Joined
Nov 6, 2019
Messages
96
none of the examples worked for me and i wanted full redirection from inside and outside.
this is doing me the favor to redirect easy url like server/emby or emby.server
- http ready
- https ready
- LAN ready
- WAN ready
- TUN ready (putty)

server name is set to local DNS name for easy evaluation.

Code:
    location /nextcloud {
        set $port EXTPORT; if ( $host = $server_name ) { set $port 444; }
        rewrite ^/nextcloud(.*)$ https://$host:$port$1 permanent;
    }
    location /emby {
        set $port EXTPORT; if ( $host = $server_name ) { set $port 8920; }
        rewrite ^/emby(.*)$ https://$host:$port$1 permanent;
    }
    location /plex {
        if ( $host = "localhost" ) { set $port EXTPORT; set $exthost $host; } #using ext ports for tunnels too
        if ( $host = $server_name ) { set $port 32400; set $exthost plex; }
        if ( $port != "" ) { rewrite ^/plex(.*)$ https://$exthost:$port$1 permanent; }
    } #DHCP, local or tunnel only
    location /radarr {
        set $port EXTPORT; if ( $host = $server_name ) { set $port 8787; }
        rewrite ^/radarr(.*)$ https://$host:$port$1 permanent;
    }
    location /sonarr {
        set $port EXTPORT; if ( $host = $server_name ) { set $port 9898; }
        rewrite ^/sonarr(.*)$ https://$host:$port$1 permanent;
    }
    location /jackett {
        if ( $host = "localhost" ) { set $port EXTPORT; }
        if ( $host = $server_name ) { set $port 9117; }
        if ( $port != "" ) { rewrite ^/jackett(.*)$ http://$host:$port$1 permanent; }
    } #local or tunnel only
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
Has anyone figured out how to properly reverse proxy Plex? Just trying to figure out a way to access my PMS from my work network that currently blocks my server. I can get into Plex.TV just fine but it won't load my server itself.
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
For those running Radarr and just had it upgrade to v3, make sure you update your proxy_setup.conf to:
Code:
location /radarr { proxy_pass http://172.16.1.252:7878; 
proxy_redirect off;
proxy_set_header Host $host; 
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
proxy_http_version 1.1; 
proxy_set_header Upgrade $http_upgrade; 
proxy_set_header Connection $http_connection; 
} 
 

sretalla

Powered by Neutrality
Moderator
Joined
Jan 1, 2016
Messages
9,702
Has anyone figured out how to properly reverse proxy Plex? Just trying to figure out a way to access my PMS from my work network that currently blocks my server. I can get into Plex.TV just fine but it won't load my server itself.
This one is probably the best:
 

AirborneTrooper

Contributor
Joined
Jun 20, 2014
Messages
148
This one is probably the best:
It seems like much more of a hassle than needed just to be able to sneak plex at work. I just use my phone for now. Since Covid hit, I'm only in the office a few times a month.
 
Last edited:

sretalla

Powered by Neutrality
Moderator
Joined
Jan 1, 2016
Messages
9,702
It seems like much more of a hassle than needed just to be able to sneak plex at work
It's mostly just copy and paste into the nginx config... not that hard, but I get your point... use case is marginal.
 
Top