User Tools

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
selfhost:nginx [2024/08/27 13:12] willyselfhost:nginx [2025/03/13 09:29] (current) – external edit 127.0.0.1
Line 1: Line 1:
-====== The Reverse Proxy concept ======+====== F) The Reverse Proxy concept ======
  
 The use of a **reverse proxy** is the key at the foundation of ensuring security, isolation and flexibility in accessing your self-hosted services. The use of a **reverse proxy** is the key at the foundation of ensuring security, isolation and flexibility in accessing your self-hosted services.
  
-A reverse-proxy is a web server that sits in the middle and handles all requests toward your services adding, on top, layers of encyrption (HTTPS/SSL), authentication, load-balancing and security. If your services are properly written (not too many, but the best ones are) they will accept your reverse-proxy authentication directly without even the need to create users for each service, in this case your reverse-proxy will also be your SSO (Single Sign On) solution. More on this on the dedicated page [[selfhost:sso|Single Sign On]], but keep reading this page first.+A reverse-proxy is a web server that sits in the middle and handles all requests toward your services adding, on top, layers of encryption (HTTPS/SSL), authentication, load-balancing and security. If your services are properly written (not too many, but the best ones are) they will accept your SSO authentication directly without even the need to create users for each service, in this case your reverse-proxy will also cater for your SSO (Single Sign On) solution . More on this on the dedicated page [[selfhost:sso|Single Sign On]], but keep reading this page first.
  
-The reverse-proxy will also take care of handling HTTP/SSL certificates in one centralized place making it much easier to configure all your services without HTTPS then converting seamlessly all the HTTP traffic to HTTPS. It's much easier to manage all the certificates in one place rather than depending on each service capability to handle HTTPS independently.+The reverse-proxy will take care of handling HTTPS/SSL certificates in one centralized place making it much easier to configure all your services without HTTPS then converting seamlessly all the HTTP traffic to HTTPS. It's much easier to manage all the certificates in one place rather than depending on each service capability to handle HTTPS independently.
  
 Also, using a well known, solid and proven web server will alleviate the risk that each service might expose a poorly written, non-scalable or worse, internal web server to end users.  Also, using a well known, solid and proven web server will alleviate the risk that each service might expose a poorly written, non-scalable or worse, internal web server to end users. 
Line 14: Line 14:
  
 My choice for a web server in this case is [[https://nginx.org|NGINX]] between the many available as Open Source because:  My choice for a web server in this case is [[https://nginx.org|NGINX]] between the many available as Open Source because: 
-  * It's much easier than [[https://www.apache.org|Apache]] to setup as a reverse-proxy, also less resource hungry. +  * It's much easier than [[https://www.apache.org|Apache]] to setup as a reverse-proxy, also less resource hungry, and works with more SSOs than Apache
-  * It has more features than [[https://caddyserver.com/|Caddy]] +  * It has more features than [[https://caddyserver.com/|Caddy]]
   * It is fully integrated in [[https://letsencrypt.org|Let's Encrypt]] SSL infrastructure / CertBot script   * It is fully integrated in [[https://letsencrypt.org|Let's Encrypt]] SSL infrastructure / CertBot script
  
-In general NGINX is fully featured but still very lightweight and secure HTTP server that shines as reverse-proxy. If you need to add more features, like [[https://www.php.net|PHP]] support or FastCGI, NGINX will support you without the need for an additional service on your server+In general NGINX is fully featured but still very lightweight and secure HTTP server that shines as reverse-proxy. If you need to add more features, like [[https://www.php.net|PHP]] support or FastCGI, NGINX will support you but with a little bit more effort than Apache.
  
 ===== Base URLs and sub-domains ===== ===== Base URLs and sub-domains =====
  
-There are two different philosophies on how to host services: serve as a sub-path of a domain, or use sub-domains. I used to like best the //sub-path// approach, but indeed a good mix of the two ways is preferrable.+There are two different philosophies on how to host services: serve as a sub-path of a domain, or use sub-domains. I used to like best the //sub-path// approach, but indeed a good mix of the two ways is preferable.
  
 Let's assume you have your own domain **mydomain.com** and you want to expose a service called //jellyfin// (a well known media-server). You can expose it: Let's assume you have your own domain **mydomain.com** and you want to expose a service called //jellyfin// (a well known media-server). You can expose it:
Line 33: Line 33:
   * Pros: only one domain needed, no need to create sub-domains   * Pros: only one domain needed, no need to create sub-domains
   * Pros: the service existence is unknown to anybody not authorized   * Pros: the service existence is unknown to anybody not authorized
-  * Cons: each service must support Base URL setting +  * Cons: each service must support Base URL setting (well, not all do!) 
-  * Cons: all services must wither support or not support SSO +  * Cons: SSO support must be somehow consistent to avoid headaches (well, SSO support is still spotty today!) 
-  * Cons: security wise, cookies and CORS can bring uninstended vulnerabilities between services. +  * Cons: security wise, cookies and CORS can bring unintended vulnerabilities between services, because they all share the same subdomain
-  * Cons: all services share the same HTTPS certificate (less secure)+  * Cons: all services share the same HTTPS certificate.
  
 As a **sub-domain**: As a **sub-domain**:
Line 46: Line 46:
   * Cons: also public knowledge because there are services indexing all existing certificates.   * Cons: also public knowledge because there are services indexing all existing certificates.
  
-__Note:__ you can create //wildcard// certificates that will match any subdomain, but there are drawbacks to this and it's not a good idea, security wise. You can still mitigate the one certificate per subdomain by adding each subdomain to the same certificate of course, but you will still need to extend your certificate each time you add a subdomain.+__Note:__ you can create //wildcard// certificates that will match any subdomain, but there are drawbacks to this and it's not a good idea, security wise. You can still mitigate the one certificate per subdomain by adding each subdomain to the same certificate of course, but you will still need to extend your certificate each time you add a subdomain: this is my approach.
  
-To make a story short, i go with subdomains for well separated services, while going with sub-paths when sharing stuff that kind belongs together. Also, a deciding factor is wether the selected services do support SSO properly or not.+To make a story short, i go with subdomains for well separated services, while going with sub-paths when sharing stuff that kind belongs together. Also, a deciding factor is whether the selected services do support SSO properly or not.
  
  
-===== Reverse Proxy propagation to external world =====+===== Reverse Proxy propagation =====
  
-The reverse proxy is installed on the local server, you should have already guessed that remote access is performed using the SSH tunnelling described in the [[selfhost:ssh_tunnel|specific page]]. The underlying idea is that you will have your reverse proxy listening to different portsand these ports will be forwarded to your external server using the SSH tunnels. Differentiating the ports is required to be able to apply SSO authentication depending on where your user connects from.+The reverse proxy is installed on the local server, i assume your local server is reachable from remote (see [[networking:external_access|Remote Access to your Home Server]]).  
 + 
 +The reverse proxy will need to be accessible to both the internal users and the external users. You could setup two different proxies, but i prefer to have only one listening to both worlds. I will assume that there might be differences between internal and external users in terms of authentication or service availability. The underlying idea is that you will have your reverse proxy listening to different ports: one for internal access and one for external access.
  
 The setup i am describing uses three different ports: The setup i am describing uses three different ports:
   * Port 80: both to local and remote, will just be a redirect to HTTPS   * Port 80: both to local and remote, will just be a redirect to HTTPS
-  * Port 443: standard HTTPS for **internal** access, no PAM authentication +  * Port 443: standard HTTPS for **internal** access 
-  * Port 8443: HTTPS with SSO authentication for **external** access +  * Port 8443: HTTPS for **external** access 
  
 **Note:** for Let's Encrypt CertBot to work properly you **need** to redirect **both** port 80 and 443 from your external server to your internal server. CertBot will shutdown your NGINX and spin a custom NGINX server that you cannot tweak so it's critical that your SSH tunnels are properly forwarding ports 80 and 443 from the external server to the internal one, or it will not work. **Note:** for Let's Encrypt CertBot to work properly you **need** to redirect **both** port 80 and 443 from your external server to your internal server. CertBot will shutdown your NGINX and spin a custom NGINX server that you cannot tweak so it's critical that your SSH tunnels are properly forwarding ports 80 and 443 from the external server to the internal one, or it will not work.
Line 65: Line 67:
 ===== Installing NGINX ===== ===== Installing NGINX =====
  
-NGINX installation on the home server is pretty straightforward, but you need to enable some specific modules, the //pam// authentication modulebecause that will link NGINX authentication to your home server users directly, without the need to create more users and passwords. If you prefer to use a different authentication, like //basic_auth//, i leave this out to you.+NGINX installation on the home server is pretty straightforward, but you need to enable some specific modules
 +  * //auth_request//: needed for SSO like authelia 
 +  * //auth_pam//: needed for PAM SSO 
 +  * //sub// is used to allow substitutions inside the pages proxiedto fix web applications that don't play well with reverse-proxies 
 +  * //gunzip// is used to unzip the requests and let the //sub// module works also on compressed requests 
 +  * //realip// is needed by SSO like authelia 
 + 
 +While NGINX support WebDAV, i strongly suggest you __dont__ enable it as you will not be using it. NGINX WebDAV support is lacking and not really recomended.
  
 So create the file **/etc/portage/package.use/nginx** with the following lines: So create the file **/etc/portage/package.use/nginx** with the following lines:
Line 73: Line 82:
 </file> </file>
  
-Let's see the modules you are enabling here: +Note: you might want to tweak the second line to your needs, see the [[https://wiki.gentoo.org/wiki/Nginx|flags for nginx]] and adapt. 
-  * //auth_request//: needed for SSO like authelia +
-  * //auth_pam//: needed for PAM SSO +
-  * //dav// and //dav_ext//: needed for WebDAV support (optional) +
-  * //sub// is used to allow substitutions inside the pages proxied, to fix web applications that don't play well with reverse-proxies +
-  * //gunzip// is used to unzip the requests and let the //sub// module works also on compressed requests +
- +
-Note: you might want to tweak the second line to your needs, see the [[https://wiki.gentoo.org/wiki/Nginx|flags for nginx]] and adapt. Specially the dav and dav_ext modules can be omitted unless you need them (i don't).+
  
 Now install nginx: Now install nginx:
 <code bash> <code bash>
- > emerge -v nginx+emerge -v nginx
 </code> </code>
 +
 +You can start it after you have configured it.
  
  
Line 94: Line 98:
 Assumptions: Assumptions:
   * Your domain is **mydomain.com**, and it has a static landing page under __/var/www/html/index.html__   * Your domain is **mydomain.com**, and it has a static landing page under __/var/www/html/index.html__
-  * Your service X is reachable under **https://mydomain.com/serviceX** +  * Your service X is reachable under **https://mydomain.com/serviceX** (subpath) 
-  * Your service Y is reachable under **https://y.mydomain.com**+  * Your service Y is reachable under **https://y.mydomain.com** (subdomain)
   * All HTTP traffic is redirected to HTTPS   * All HTTP traffic is redirected to HTTPS
 +  * You have a single Let's Encrypt SSL certificate which covers all the subdomains of your domain (either a wildcard or a comulative cert it's up to you)
 +  * You might have more than one main domain
  
-You will create a set of subfolders stemming from the main domain, then one folder for each sub-domains, and inside each folder one configuration file for each sub-path served un that sub-domain.+The top-level **mydomain.com** will have it's own folder, then you will create a set of sub-folders stemming from the main domain, one folder for each sub-domains, and inside each folder one configuration file for each sub-path served on that sub-domain.
  
 So you will need the following files: So you will need the following files:
Line 109: Line 115:
  
 The **certbot.conf** file will be created later on, the specific SSO config files are described in the [[selfhost:sso|Authentication]] page. The **certbot.conf** file will be created later on, the specific SSO config files are described in the [[selfhost:sso|Authentication]] page.
 +
  
 ==== Top-level configuration  ==== ==== Top-level configuration  ====
Line 149: Line 156:
         proxy_headers_hash_bucket_size 128;         proxy_headers_hash_bucket_size 128;
  
-        # Add domains here (only the main config file for each subdomain!)+        # Add domains here (only the main config file for each domain!)
         include com.mydomain/mydomain.conf;         include com.mydomain/mydomain.conf;
 +        
 +        # This is for SSL and needs to be included only once for all the domains
 +        include /etc/letsencrypt/options-ssl-nginx.conf;
 } }
 </file> </file>
  
 This will set your defaults for every service and site served by this reverse proxy, then will load the //mydomain.com// specific configuration file. This will set your defaults for every service and site served by this reverse proxy, then will load the //mydomain.com// specific configuration file.
 +
  
 ==== mydomain.com configuration  ==== ==== mydomain.com configuration  ====
Line 166: Line 177:
 # simple catch-all server for the domain # simple catch-all server for the domain
 server { server {
-        server_name 10.0.0.1 mydomain.com;+       # You might want to specify also the internal  
 +        server_name mydomain.com; 
 +        # Port for users from outside
         listen 8443 ssl;         listen 8443 ssl;
 +        # Port for users from inside
         listen 443 ssl;         listen 443 ssl;
         http2 on;         http2 on;
Line 177: Line 191:
  
        # include all sub-paths for mydomain.com:        # include all sub-paths for mydomain.com:
-       include serviceX.conf+       include serviceX.conf
 + 
 +       # include HTTPS certs stuff: 
 +       include org.gardiol/certbot.conf;
 } }
  
 # include all sub-domains entry points: # include all sub-domains entry points:
 include com.mydomain/y/y.conf; include com.mydomain/y/y.conf;
- 
-# include HTTS certs stuff: 
-include com.mydomain/certbot.conf; 
 </file> </file>
  
-This will create the basic setup for your base domain name. I have assumed you want a static landing page, but you might put a //redirect// to service Y or service X...+This will create the basic setup for your base domain name. I have assumed you want a static landing page, but you might put a //redirect// to service Y or service X... Or add a dashboard, of course protected by your SSO...
  
  
 ==== sub-domains configuration  ==== ==== sub-domains configuration  ====
  
-It sohuld be clear now that each sub-domain will have it's own sub-folder and contain at least one (or more) configuration files inside for each sub-path, like the one for serviceY. +It should be clear now that each sub-domain will have it's own sub-folder and contain at least one (or more) configuration files inside for each sub-path, like the one for serviceY. 
  
 I will assume that //serviceY// perform it's own authentication and cannot use SSO: I will assume that //serviceY// perform it's own authentication and cannot use SSO:
 <file - y.conf> <file - y.conf>
 server { server {
-        server_name y.mydomain.com; +       server_name y.mydomain.com; 
-        listen 8443 ssl; # external access +       listen 8443 ssl; # external access 
-        listen 443 ssl; # internal access +       listen 443 ssl; # internal access 
-        access_log /var/log/nginx/y.mydomain.com_access_log main; +       access_log /var/log/nginx/y.mydomain.com_access_log main; 
-        error_log /var/log/nginx/y.mydomain.com_error_log info; +       error_log /var/log/nginx/y.mydomain.com_error_log info; 
-        location / { +       location / { 
-                #Generic proxy pass to proxied service +               #Generic proxy pass to proxied service 
-                proxy_pass http://127.0.0.1:8000; +               proxy_pass http://127.0.0.1:8000; 
-        }+       } 
 +       # include HTTPS certs stuff: 
 +       include org.gardiol/certbot.conf;
 } }
 </file> </file>
Line 212: Line 228:
  
  
-==== Internal or External access for services ====+==== Differentiate between Internal or External access for services ====
  
 In my setup i have some differences when a service is accessed from //within// the home network, or from //outside// the home network. In my setup i have some differences when a service is accessed from //within// the home network, or from //outside// the home network.
  
-The key point is that //external// access comes trough port 8443, while //internal// acces coms trough port 443. This allows you to differentiate your setup with __server__ blocks.+The key point is that //external// access comes trough port 8443, while //internal// aces comes trough port 443. This allows you to differentiate your setup with __server__ blocks.
  
 So, for example, a service _only_ available inside the home network will have something like: So, for example, a service _only_ available inside the home network will have something like:
Line 230: Line 246:
                 proxy_pass http://127.0.0.1:8000;                 proxy_pass http://127.0.0.1:8000;
         }         }
 +       # include HTTPS certs stuff:
 +       include org.gardiol/certbot.conf;
 } }
 </code> </code>
Line 246: Line 264:
                 proxy_pass http://127.0.0.1:8000;                 proxy_pass http://127.0.0.1:8000;
         }         }
 +       # include HTTPS certs stuff:
 +       include org.gardiol/certbot.conf;
 } }
 </code> </code>
Line 261: Line 281:
                 proxy_pass http://127.0.0.1:8000;                 proxy_pass http://127.0.0.1:8000;
         }         }
 +       # include HTTPS certs stuff:
 +       include org.gardiol/certbot.conf;
 } }
 server { server {
Line 273: Line 295:
                 proxy_pass http://127.0.0.1:8000;                 proxy_pass http://127.0.0.1:8000;
         }         }
 +       # include HTTPS certs stuff:
 +       include org.gardiol/certbot.conf;
 } }
 </code> </code>
 +
 +In this case, you can even optimize more by moving the **location** lines, which are identical, inside another file that you __include__ twice. Better to avoid redundancy!
  
 Of course, refer to the [[selfhost:sso|SSI]] page for more details on SSO. Of course, refer to the [[selfhost:sso|SSI]] page for more details on SSO.
Line 327: Line 353:
 Let's Encrypt certificates last 90 days, then they need to be renewed. This is automated by CertBot but you need to call it periodically. You can use crontab for this. Edit root crontab: Let's Encrypt certificates last 90 days, then they need to be renewed. This is automated by CertBot but you need to call it periodically. You can use crontab for this. Edit root crontab:
 <code bash> <code bash>
- > crontab -e+crontab -e
 </code> </code>
  
Line 341: Line 367:
  
 <code bash> <code bash>
- > rc-update add nginx default +rc-update add nginx default 
- /etc/init.d/nginx start+/etc/init.d/nginx start
 </code> </code>
 +
 +
 +
 +==== Quick and dirty script for new subdomains ====
 +
 +When you need to **add** a new subbomain to your certificate, you can copy (and adapt) the following script i use:
 +<file - certbot_script.sh>
 +#!/bin/bash
 +
 +DOMAINS="mydomain.con y.mydomain.com other.mydomain.com"
 +
 +domains=
 +for i in ${DOMAINS}
 +do
 +        domains="${domains} -d ${i}"
 +done
 +
 +certbot certonly --expand --nginx ${domains}
 +</file>
 +
 +So __FIRST__ you **update** the script adding the new domain at the end of the DOMAINS line, then you run the script and restart your NGINX.
  
  
Line 350: Line 397:
 To be able to run system scripts and, in general, [[https://en.wikipedia.org/wiki/CGI|CGIs]] on NGINX you need to do some additional configuration. NGINX is not capable of running CGI scripts at all. It has only support for [[https://en.wikipedia.org/wiki/FastCGI|FastCGI]] protocol, which is **quite different** and **not directly compatible** with standard CGI. To be able to run system scripts and, in general, [[https://en.wikipedia.org/wiki/CGI|CGIs]] on NGINX you need to do some additional configuration. NGINX is not capable of running CGI scripts at all. It has only support for [[https://en.wikipedia.org/wiki/FastCGI|FastCGI]] protocol, which is **quite different** and **not directly compatible** with standard CGI.
  
-For using CGI directly with NGGINX (another option coule be run Apache or another web server) you can install and setup [[https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/|fcgiwrap]] and it's companion spawn package:+For using CGI directly with NGINX (another option could be to run Apache or another web server in addition, but why?) you can install and setup [[https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/|fcgiwrap]] and it's companion spawn package:
 <code bash> <code bash>
 emerge www-misc/fcgiwrap www-servers/spawn-fcgi emerge www-misc/fcgiwrap www-servers/spawn-fcgi

This website uses technical cookies only. No information is shared with anybody or used in any way but provide the website in your browser.

More information