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