本帖最后由 梅钟园 于 2024-12-2 23:10 编辑
背景:
最近网站打算使用SSL证书,曾经为 RH124、RH134、RH294、RH358、CL260、DO374 等环境准备的联网更新脚本仅支持 HTTP 协议,重构全部环境不太现实(当初未考虑SSL)。
现在为兼容 HTTP 和 HTTPS,服务提供端决定使用端口复用以同时支持 HTTP 和 HTTPS,故而有此处内容分享。
此处仅分享核心配置,是经过验证能够使用的配置,具体细节不作展示,有需要可以随时与我交流。
一、端口复用
简单来说,同一端口根据请求协议(四层或七层)转发至不同后端服务,以实现根据不同协议访问同一端口时,能够到达不同后端服务。例如 18080/tcp 端口同时支持 http 和 https 访问。
使用典型的 Nginx 和 Haproxy 均可以实现。
二、构建镜像
此处使用Docker将所有业务组件均构建为容器,便于后续升级。此处默认读者已经熟悉容器技术、Dockerfile、docker-compose、Compose Files,下列仅列出核心配置。
base images:
从官方镜像构建自定义基础镜像,必要时可以从其他地方编译安装以植入更多模块(如Nginx模块)。
nginx-base:1.27.2 from nginx:1.27.2
haproxy-base:3.0.6 from haproxy:3.0.6
示例:nginx-base:1.27.2 Dockerfile 如下;根据自己需要,改时区,安装小工具等。
可以再创建一个
- FROM nginx:1.27.2
- ENV TZ="Asia/Shanghai"
- RUN mkdir -p /etc/nginx/certs.d ; \
- rm -rf /etc/localtime ; \
- ln -sv /usr/share/zoneinfo/Asia/shanghai /etc/localtime ; \
- apt update && apt install -y iproute2 lsof telnet traceroute tree curl vim && \
- apt-get clean && rm -rf /var/lib/apt/lists/*
- CMD ["nginx","-g","daemon off;"]
复制代码 None 镜像清理
- docker rmi $(docker images -f 'dangling=true' -q)
复制代码
apps images:
从自定义的基础镜像再次构建应用镜像。
nginx-webapp:n1.27.2-v1.0 from nginx-base:1.27.2
haproxy-balances:h3.0.6-v1.0 from haproxy-balances:3.0.6
nginx-balances:n1.27.2-v1.0 from nginx-base:1.27.2
nginx-webapp:n1.27.2-v1.0 from nginx-base:1.27.2
nginx-webapp:n1.27.2-v1.0 镜像构建材料(建议配置文件和证书通过挂载方式使用,应用镜像只构建网站源代码即可,不要包含太多其他信息,更不要包含机密信息)
说明:主要构建网站源代码,nginx-webapp 将同时支持 80/tcp HTTP 访问,443/tcp HTTPS 访问,也可以分成两个镜像分别支持 HTTP 和 HTTPS。
重要配置:nginx-webapp 启用 proxy_protocol ,并且配置允许从上游代理获取源IP。这一配置的上游代理服务器必须也同样启用这一功能,如上游代理为 nginx,则必须也启用 proxy_protocol,若为 Haproxy,必须 send_proxy。
否则整体网站无法访问。
- nginx-webapp/
- ├── Dockerfile
- ├── config-nginx
- │ ├── conf.d
- │ │ └── vhost.conf
- │ └── nginx.conf
- └── html
复制代码 nginx.conf -> 容器 /etc/nginx/nginx.conf
- user nginx;
- worker_processes auto;
- error_log /var/log/nginx/error.log notice;
- pid /var/run/nginx.pid;
- events {
- worker_connections 1024;
- }
- http {
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
- log_format main '$proxy_protocol_addr - $remote_addr - $remote_user [$time_local] "$request" '
- '$status $body_bytes_sent "$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- access_log /var/log/nginx/access.log main;
- sendfile on;
- #tcp_nopush on;
- keepalive_timeout 65;
- # 压缩设置
- gzip on;
- gzip_disable "msie6";
- gzip_vary on;
- gzip_proxied any;
- gzip_comp_level 6;
- gzip_buffers 16 8k;
- gzip_types text/plain text/css application/javascript application/json application/xml application/rss+xml image/svg+xml;
- map $status $status_name {
- 100 "Continue";
- 101 "Switching Protocols";
- 102 "Processing";
- 103 "Early Hints";
- 200 "OK";
- 201 "Created";
- 202 "Accepted";
- 203 "Non-Authoritative Information";
- 204 "No Content";
- 205 "Reset Content";
- 206 "Partial Content";
- 300 "Multiple Choices";
- 301 "Moved Permanently";
- 302 "Found";
- 303 "See Other";
- 304 "Not Modified";
- 305 "Use Proxy";
- 307 "Temporary Redirect";
- 308 "Permanent Redirect";
- 400 "Bad Request";
- 401 "Unauthorized";
- 403 "Forbidden";
- 404 "Not Found";
- 405 "Method Not Allowed";
- 406 "Not Acceptable";
- 407 "Proxy Authentication Required";
- 408 "Request Timeout";
- 409 "Conflict";
- 410 "Gone";
- 411 "Length Required";
- 412 "Precondition Failed";
- 413 "Payload Too Large";
- 414 "URI Too Long";
- 415 "Unsupported Media Type";
- 416 "Range Not Satisfiable";
- 417 "Expectation Failed";
- 418 "I'm a teapot";
- 429 "Too Many Requests";
- 500 "Internal Server Error";
- 501 "Not Implemented";
- 502 "Bad Gateway";
- 503 "Service Unavailable";
- 504 "Gateway Timeout";
- 505 "HTTP Version Not Supported";
- default "Unknown";
- }
- include /etc/nginx/conf.d/*.conf;
- }
复制代码 conf.d/vhost.conf -> 容器 /etc/nginx/conf.d/vhost.conf
三、核心配置
3.1 Nginx 端口复用配置
nginx-balances:n1.27.2-v1.0 from nginx-base:1.27.2
重要配置:nginx-balances 必须启用 proxy_protocol: on ,以适应 nginx-webapp
nginx.conf -> /etc/nginx/nginx.conf
- user nginx;
- worker_processes auto;
- error_log /var/log/nginx/error.log notice;
- pid /var/run/nginx.pid;
- events {
- worker_connections 1024;
- }
- # docs: https://nginx.org/en/docs/stream/ngx_stream_core_module.html
- stream {
- # docs: https://nginx.org/en/docs/stream/ngx_stream_log_module.html
- # log_format stream '$remote_addr [$time_local] '
- # '$protocol $status $bytes_sent $bytes_received '
- # '$session_time "$upstream_addr" '
- # '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
- # custom
- log_format stream '{"@access_time":"$time_iso8601",'
- '"clientip":"$remote_addr",'
- '"pid":$pid,'
- '"pro":"$protocol",'
- '"ssl_pro": "$ssl_preread_protocol",'
- '"pro":"$protocol",'
- '"stus":$status,'
- '"sent":$bytes_sent,'
- '"recv":$bytes_received,'
- '"sess_time":$session_time,'
- '"up_addr":"$upstream_addr",'
- '"up_sent":$upstream_bytes_sent,'
- '"up_recv":$upstream_bytes_received,'
- '"up_conn_time":$upstream_connect_time,'
- '"up_resp_time":"$upstream_first_byte_time",'
- '"up_sess_time":$upstream_session_time}';
- upstream http {
- server nginx-webapp:80;
- }
- upstream https {
- server nginx-webapp:443;
- }
- map $ssl_preread_protocol $upstream {
- default http;
- "TLSv1.0" https;
- "TLSv1.1" https;
- "TLSv1.2" https;
- "TLSv1.3" https;
- }
- server {
- listen 18080;
- proxy_pass $upstream;
- proxy_connect_timeout 3s;
- proxy_timeout 5s;
- ssl_preread on;
- proxy_protocol on;
- access_log /var/log/nginx/stream_access.log stream;
- error_log /var/log/nginx/stream_error.log notice;
- }
- }
- http {
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
- log_format main '$proxy_protocol_addr - $remote_addr - $remote_user [$time_local] "$request" '
- '$status $body_bytes_sent "$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- access_log /var/log/nginx/access.log main;
- sendfile on;
- #tcp_nopush on;
- keepalive_timeout 65;
- # 压缩设置
- gzip on;
- gzip_disable "msie6";
- gzip_vary on;
- gzip_proxied any;
- gzip_comp_level 6;
- gzip_buffers 16 8k;
- gzip_types text/plain text/css application/javascript application/json application/xml application/rss+xml image/svg+xml;
- map $status $status_name {
- 100 "Continue";
- 101 "Switching Protocols";
- 102 "Processing";
- 103 "Early Hints";
- 200 "OK";
- 201 "Created";
- 202 "Accepted";
- 203 "Non-Authoritative Information";
- 204 "No Content";
- 205 "Reset Content";
- 206 "Partial Content";
- 300 "Multiple Choices";
- 301 "Moved Permanently";
- 302 "Found";
- 303 "See Other";
- 304 "Not Modified";
- 305 "Use Proxy";
- 307 "Temporary Redirect";
- 308 "Permanent Redirect";
- 400 "Bad Request";
- 401 "Unauthorized";
- 403 "Forbidden";
- 404 "Not Found";
- 405 "Method Not Allowed";
- 406 "Not Acceptable";
- 407 "Proxy Authentication Required";
- 408 "Request Timeout";
- 409 "Conflict";
- 410 "Gone";
- 411 "Length Required";
- 412 "Precondition Failed";
- 413 "Payload Too Large";
- 414 "URI Too Long";
- 415 "Unsupported Media Type";
- 416 "Range Not Satisfiable";
- 417 "Expectation Failed";
- 418 "I'm a teapot";
- 429 "Too Many Requests";
- 500 "Internal Server Error";
- 501 "Not Implemented";
- 502 "Bad Gateway";
- 503 "Service Unavailable";
- 504 "Gateway Timeout";
- 505 "HTTP Version Not Supported";
- default "Unknown";
- }
- include /etc/nginx/conf.d/*.conf;
- }
复制代码
3.1 Haproxy 端口复用配置
haproxy-balances:h3.0.6-v1.0 from haproxy-balances:3.0.6
重要配置:Haproxy-balances 必须启用 send-proxy ,以适应 nginx-webapp
- global
- log /dev/stdout local0
- maxconn 2000
- user haproxy
- group haproxy
- daemon
- defaults
- log global
- option httplog
- option dontlognull
- timeout http-request 30s
- timeout queue 10s
- timeout connect 10s
- timeout client 1m
- timeout server 1m
- timeout http-keep-alive 10s
- timeout check 10s
- #frontend stats
- # bind *:18081 ssl crt /var/lib/haproxy/certs.d/server.pem
- # bind *:18081
- # bind *:18081 ssl crt /var/lib/haproxy/certs.d/server.pem
- # mode http
- # stats enable
- # stats uri /haproxy_stats
- # stats realm Haproxy\ Statistics
- # stats auth admin:password
- # stats show-node
- # stats show-legends
- # stats hide-version
- frontend main
- bind *:18080
- mode tcp
- option tcplog
- log-format %ft\ %b/%s
- tcp-request inspect-delay 5s
- # acl is_ssh req.payload(0,3) -m bin 535348
- # acl is_rdp req.payload(0,3) -m bin 030000
- # acl is_telnet req.payload(0,4) -m bin 54656c6e
- # acl is_smb req.payload(0,4) -m bin 4d5a9000
- # acl is_ftp_user req.payload(0,4) -m bin 55534552
- # acl is_ftp_pass req.payload(0,4) -m bin 50415353
- # acl is_smtp_helo req.payload(0,4) -m bin 48454c4f
- # acl is_pop3_user req.payload(0,4) -m bin 55534552
- # acl is_pop3_pass req.payload(0,4) -m bin 50415353
- # acl is_imap_login req.payload(0,5) -m bin 4c4f4749
- # acl is_dns_query req.payload(0,2) -m bin 0000
- # acl is_ldap req.payload(0,4) -m bin 30303030
- acl is_https req.payload(0,3) -m bin 160301
- # HTTPS
- acl is_http req.payload(0,3) -m bin 474554 504f53 505554 44454c 4f5054 484541 434f4e 545241
- # GET POST PUT DELETE OPTIONS HEAD CONNECT TRACE
- #acl is_https req.ssl_hello_type 1
- tcp-request content accept if is_https
- # tcp-request content accept if { req.ssl_hello_type 1 }
- tcp-request content accept if is_http
- use_backend backend_http if is_http
- use_backend backend_https if is_https
- default_backend backend_http
- backend backend_http
- mode tcp
- balance roundrobin
- server backend1 nginx-webapp:80 maxconn 10 check inter 3s send-proxy
- backend backend_https
- mode tcp
- balance roundrobin
- server backend1 nginx-webapp:443 maxconn 10 check inter 3s send-proxy
复制代码
四、docker-compose compose file
compose file 示例
- name: nginx-scripts-app
- # docker-compose v20.3
- services:
- nginx-webapp:
- image: nginx-webapp:n1.27.2-v1.0
- expose:
- - "80"
- - "443"
- volumes:
- - ./certs.d:/etc/nginx/certs.d:ro
- - ./nginx-webapp/conf.d:/etc/nginx/conf.d
- - ./nginx-webapp/nginx.conf:/etc/nginx/nginx.conf
- - ./nginx-webapp/html/:/usr/share/nginx/html
- - ./nginx-webapp/logs/:/var/log/nginx
- networks:
- - nginx-scripts
- haproxy-balances:
- image: haproxy-balances:h3.0.6-v1.0
- expose:
- - "18080"
- ports:
- - "18081:18080"
- volumes:
- - ./haproxy-balances/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- networks:
- - nginx-scripts
- nginx-balances:
- image: nginx-webapps:1.27.2
- expose:
- - "80"
- - "443"
- ports:
- - "18080:18080"
- volumes:
- #- ./certs.d:/etc/nginx/certs.d:ro
- - ./nginx-balances/conf.d:/etc/nginx/conf.d
- - ./nginx-balances/nginx.conf:/etc/nginx/nginx.conf
- - ./nginx-balances/html/:/usr/share/nginx/html
- - ./nginx-balances/logs/:/var/log/nginx
- networks:
- - nginx-scripts
- networks:
- nginx-scripts:
- driver: bridge
- ipam:
- driver: default
- config:
- - subnet: 172.18.0.0/16
- ip_range: 172.18.18.0/24
- gateway: 172.18.18.254
复制代码
|