Homelab | Low-level design –Nginx Reverse Proxy

1 Introduction

In the chapter “Architecture design and implementation – High-level design”, the implementation of the cloud part focuses on Nginx Reverse Proxy, according to the policy, part of the traffic is processed in the “cloud local”, part of the traffic is forwarded to another local in the “Homelab” through FRP. Some traffic is processed ‘cloud local’ and some traffic is forwarded to another local ‘Homelab’ via FRP.

Based on the above diagram, the host on the cloud deploys the following applications:

  • Typecho blog, deployed on the host via LNMP.
  • WordPress blog, deployed via Docker
  • FRP server, deployed via Docker
  • Letsencrypt, deployed via Docker
  • portainer, deployed via Docker
root@myblog:~# docker ps
CONTAINER ID   IMAGE                           COMMAND                  CREATED        STATUS        PORTS                                          NAMES
a943473882e5   snowdreamtech/frps              "/bin/sh -c '/usr/bi…"   5 months ago   Up 3 days                                                    frps
83e72086e158   portainer/portainer-ce:latest   "/portainer"             5 months ago   Up 2 months   8000/tcp, 9443/tcp, 127.0.0.1:9000->9000/tcp   portainer
05408a9f98d8   mysql:5.7                       "docker-entrypoint.s…"   5 months ago   Up 2 months   33060/tcp, 127.0.0.1:13306->3306/tcp           myblog-db-1
2137b27bdf51   linuxserver/swag                "/init"                  5 months ago   Up 11 days    80/tcp, 443/tcp                                letsencrypt
cb2a2593f729   wordpress:latest                "docker-entrypoint.s…"   5 months ago   Up 2 months   0.0.0.0:8001->80/tcp, :::8001->80/tcp          myblog-wordpress-1

2 Deployment

1 Typecho blog, LNMP deployment on the host machine

[How To Install Linux, Nginx, MySQL, PHP (LNMP stack) on Ubuntu 20.04]

2 WordPress blogs, deployed via Docker

version: '2'

services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: ${MYSQL_DATABASE_PASSWORD:-wordpress007}
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress001
       MYSQL_PASSWORD: wordpress007

   wordpress:
     image: wordpress:latest
     ports:
       - 8001:80
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress001
       WORDPRESS_DB_PASSWORD: wordpress007

volumes:
    db_data:

3 FRP server, deployed via Docker

docker run --restart=always --network host -d -v /root/frps.ini:/etc/frp/frps.ini --name frps snowdreamtech/frps

4 Letsencrypt, deployed via Docker

https://homelab.samliu.tech/archives/lets-encrypt-%E9%80%9A%E9%85%8D%E7%AC%A6%E8%AF%81%E4%B9%A6.html

5 portainer,deployed via Docker

docker run -d --network host --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

6 Nginx Reverse Proxy Configuration

The previous based on the installation of Nginx, modify the configuration before, you need to understand the Nginx configuration file structure relationship.
Understanding the Nginx Configuration File Structure and Configuration Contexts

root@myblog:~# tree /etc/nginx/
/etc/nginx/
├── conf.d
│   └── ssl-nginx.conf
├── fastcgi.conf
├── fastcgi_params
├── koi-utf
├── koi-win
├── mime.types
├── modules-available
├── modules-enabled
│   ├── 50-mod-http-image-filter.conf -> /usr/share/nginx/modules-available/mod-http-image-filter.conf
│   ├── 50-mod-http-xslt-filter.conf -> /usr/share/nginx/modules-available/mod-http-xslt-filter.conf
│   ├── 50-mod-mail.conf -> /usr/share/nginx/modules-available/mod-mail.conf
│   └── 50-mod-stream.conf -> /usr/share/nginx/modules-available/mod-stream.conf
├── nginx.conf
├── nginx.conf.bak
├── nginx.conf.save
├── proxy_params
├── scgi_params
├── sites-available
│   ├── default
│   ├── http
│   ├── http.bak
│   ├── https
│   └── https.bak
├── sites-enabled
│   ├── http -> /etc/nginx/sites-available/http
│   └── https -> /etc/nginx/sites-available/https
├── snippets
│   ├── fastcgi-php.conf
│   └── snakeoil.conf
├── uwsgi_params
├── win-utf
└── wireguard.stream.conf
  • /etc/nginx/nginx.conf : The main configuration file, which nests several sub-configuration files under different paths, via include statements.
root@myblog:~# more /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##
        client_max_body_size 30m;
        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        # ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        # ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

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

        ##
        # Gzip Settings
        ##

        gzip on;

        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_buffers 16 8k;
        gzip_http_version 1.1;
        gzip_min_length 256;
        gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}

#stream {
#    include /etc/nginx/wireguard.stream.conf;
#}

#mail {
#       # See sample authentication script at:
#       # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
#       # auth_http localhost/auth.php;
#       # pop3_capabilities "TOP" "USER";
#       # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
#       server {
#               listen     localhost:110;
#               protocol   pop3;
#               proxy      on;
#       }
#
#       server {
#               listen     localhost:143;
#               protocol   imap;
#               proxy      on;
#       }
#}
  • sites-available: This folder is where HTTP configuration files are stored, and specific configuration files need to be soft-linked to the sites-enabled folder for them to work.
  • sites-enabled:This folder contains all the relevant configurations for HTTP that are actually in effect.
  • conf.d: About where other HTTP subconfiguration files are stored, e.g. SSL configuration
root@myblog:~# more /etc/nginx/conf.d/ssl-nginx.conf
    ########################################################################
    # from https://cipherlist.eu/                                            #
    ########################################################################

    ssl_protocols TLSv1.3;# Requires nginx >= 1.13.0 else use TLSv1.2
    ssl_prefer_server_ciphers on;
    ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
    ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
    ssl_session_timeout  10m;
    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 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    # Disable preloading HSTS for now.  You can use the commented out header line that includes
    # the "preload" directive if you understand the implications.
    #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    ##################################
    # END https://cipherlist.eu/ BLOCK #
    ##################################
  • For reverse proxy configuration for WEB traffic, focus on the sites-enabled folder.
root@myblog:~# more /etc/nginx/sites-enabled/http
server {
    listen 80 default_server;
    #listen [::]:80;
    server_name _;
    return 412;
    #access_log /var/www/your_domain3/your_domain3_http.log;
}

server {
    listen 80;
    #listen [::]:80;
    server_name *.samliu.tech *.duckdns.org;
    return 301 https://$host$request_uri;
    #access_log /var/www/your_domain3/your_domain3_http.log;
}

HTTP configuration logic:
For incoming HTTP requests, the domain name (host field) is checked, and the exact match condition takes precedence over others, so for .samliu.tech .duckdns.org, redirects to HTTPS traffic; for server_name _, all other domains, returns 412 error code.

root@myblog:~# more /etc/nginx/sites-enabled/https
server {
    listen 443 ssl http2 default_server;
    server_name _;
    return 412;
    ssl_certificate /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/fullchain.pem;
    ssl_certificate_key /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
}


server {
    listen 185.186.146.68:9000 ssl http2;
    server_name $host;
    ssl_certificate /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/fullchain.pem;
    ssl_certificate_key /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    #include /etc/nginx/conf.d/ssl-nginx.conf

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        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_set_header X-Forwarded-Proto $scheme;
    }
    #access_log /var/www/your_domain2/your_domain2_https.log;


}


server {
    listen 443 ssl http2;
    #listen [::]:443 ssl http2;
    server_name typecho.samliu.tech homelab.samliu.tech;
    root /var/www/typechooo;
    # include typecho.conf;
    index index.html index.htm index.php;

    ssl_certificate /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/fullchain.pem;
    ssl_certificate_key /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    #include /etc/nginx/conf.d/ssl-nginx.conf

    if (!-e $request_filename) {
        rewrite ^(.*)$ /index.php$1 last;
        }

    location / {
        try_files $uri $uri/ =404;
        }

    location ~ .*\.php(\/.*)*$ {
        set $path_info "";
        set $real_script_name $fastcgi_script_name;
        if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
        set $real_script_name $1;
        set $path_info $2;
        }
        fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
        fastcgi_param SCRIPT_NAME $real_script_name;
        fastcgi_param PATH_INFO $path_info;

        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
    #access_log /var/www/your_domain1/your_domain1_https.log;
}




server {
    listen 443 ssl http2;
    #listen [::]:443 ssl http2;
    server_name blog.samliu.tech;

    ssl_certificate /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/fullchain.pem;
    ssl_certificate_key /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    #include /etc/nginx/conf.d/ssl-nginx.conf

    ########################################################################

    location / {
        proxy_pass http://127.0.0.1:8001;
        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_set_header X-Forwarded-Proto $scheme;
    }
    #access_log /var/www/your_domain2/your_domain2_https.log;
}



server {
    listen 443 ssl http2;
    #listen [::]:443 ssl http2;
    server_name *.samliu.tech *.duckdns.org;

    ssl_certificate /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/fullchain.pem;
    ssl_certificate_key /root/letsencrypt-config/etc/letsencrypt/live/samliu.tech/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    #include /etc/nginx/conf.d/ssl-nginx.conf

    ########################################################################

    location / {
        proxy_pass http://127.0.0.1:980;
        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        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_set_header X-Forwarded-Proto $scheme;
    }
    #access_log /var/www/your_domain2/your_domain2_https.log;
}

HTTPS configuration logic: Upon receipt of HTTPS situation, the breakdown conditions are prioritized with others, retaining all original HTTP header information for websocket support, etc., and the same SSL configuration information is stripped to /etc/nginx/conf.d/ssl-nginx.conf.

  • listen 185.186.146.68:9000 ssl http2 match the IP+port,then forward to the http://127.0.0.1:9000,it’s used for the portainer
  • typecho.samliu.tech homelab.samliu.tech match the domain,forward to the Typecho website,root/var/www/typechooo,which is the local servises in cloud host。
  • blog.samliu.tech match the domain ,then forward to the http://127.0.0.1:8001,it’s the WordPress website deployed via docker
  • .samliu.tech .duckdns.org match the domain,forward to the http://127.0.0.1:980,which is the FRP server deployed via docker which is L2 Reverse Agents
  • server_name _ for All other remaining HTTPS requests return the return 412 error code。

3 Other/references

How To Install WordPress With Docker Compose

https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-with-docker-compose

How to Set Up SSH Keys on Ubuntu 20.04
https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-ubuntu-20-04

How To Install Linux, Nginx, MySQL, PHP (LEMP stack) on Ubuntu 20.04
https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-ubuntu-20-04

How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 20.04 Server
https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-as-a-web-server-and-reverse-proxy-for-apache-on-one-ubuntu-20-04-server

How To Improve Website Performance Using gzip and Nginx on Ubuntu 20.04
https://www.digitalocean.com/community/tutorials/how-to-improve-website-performance-using-gzip-and-nginx-on-ubuntu-20-04

Related Posts

Leave a Reply

Your email address will not be published.