Homelab | 架构设计与实现-Low-level design --Nginx Reverse Proxy

一 介绍

关于 “架构设计与实现-High-level design”篇章里,云上部分的实现重点是-Nginx Reverse Proxy ,依据策略,部分流量在“云本地”处理,部分流量通过 FRP 转发到‘Homelab’另一个本地。

请输入图片描述

依据上图,云上主机部署如下应用:

  1. Typecho 博客,LNMP 方式部署在宿主机上
  2. Wordpress 博客,通过 Docker 部署
  3. FRP server ,通过 Docker 部署
  4. Letsencrypt, 通过 docker 部署
  5. portainer ,通过 Docker 部署
[email protected]:~# 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

二 部署

1 Typecho 博客,LNMP 方式部署在宿主机

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

2 Wordpress 博客,通过 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 ,通过 Docker 部署

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

4 Letsencrypt, 通过 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 ,通过 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 反向代理配置

前面依据安装好了 Nginx ,修改配置之前,需要了解下 Nginx 配置文件结构关系。 Understanding the Nginx Configuration File Structure and Configuration Contexts

[email protected]:~# 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: 主配置文件,里面嵌套了多个不同路径下的子配置文件,通过 include 语句。
[email protected]:~# 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: 该文件夹是存放关于 HTTP 配置文件的地方,特定配置文件需要软链接到 sites-enabled 文件夹才生效
  • sites-enabled:该文件夹包括实际生效的,关于 HTTP 的所有相关配置
  • conf.d: 关于 HTTP 其他子配置文件存放地,例如 SSL 配置
[email protected]:~# 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 #
##################################

  • 关于 WEB 流量的反向代理配置,着重关注 sites-enabled 文件夹。
[email protected]:~# 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 配置逻辑: 针对收到的 HTTP 请求,检查域名( host 字段),精确匹配条件优先于其他,因此,对于*.samliu.tech *.duckdns.org ,重定向到 HTTPS 流量;对于 server_name _,其他所有域名,返回 412 错误码。

[email protected]:~# 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 配置逻辑: 收到 HTTPS 情况后,明细条件优先与其他,保留所有原始 HTTP header 信息以便支持 websocket 等,相同的 SSL 配置信息剥离到 /etc/nginx/conf.d/ssl-nginx.conf 。

-listen 185.186.146.68:9000 ssl http2 匹配该 IP+端口,转发到 http://127.0.0.1:9000 ,此处为 portainer

-typecho.samliu.tech homelab.samliu.tech 匹配该域名,转发到 Typecho 网站,root /var/www/typechooo ,此处是部署在本地的服务,非反向代理服务。

-blog.samliu.tech 匹配该域名,转发到 http://127.0.0.1:8001 ,此处为 Wordpress 网站,docker 部署的

-*.samliu.tech *.duckdns.org 匹配该域名,转发到 http://127.0.0.1:980 ,此处为 FRP server 服务,docker 部署的,作为二级反向代理

-server_name _ 剩下的所有其他 HTTPS 请求,返回 return 412 错误码。 [/scode]

三 其他 /引用

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