添加Certbot服务,并为Nginx和Certbot添加证书相关卷。
services:
# GridBNB 交易机器人服务
gridbnb-bot:
build:
context: .
dockerfile: Dockerfile
container_name: gridbnb-bot
restart: always
env_file:
- .env
# 内部端口,不直接暴露给外部
expose:
- "58181"
volumes:
- ./:/app
- ./data:/app/data # 持久化数据目录
networks:
- gridbnb-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:58181/health"]
interval: 30s
timeout: 10s
retries: 3
# Nginx 反向代理服务
nginx:
image: nginx:alpine
container_name: gridbnb-nginx
restart: always
ports:
- "80:80" # 外部访问端口,用于HTTP和Certbot验证
- "443:443" # HTTPS端口
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/logs:/var/log/nginx
- ./certbot/conf:/etc/letsencrypt:ro # 挂载SSL证书到Nginx(只读)
- ./certbot/www:/var/www/certbot:rw # Certbot webroot,用于验证
depends_on:
- gridbnb-bot
networks:
- gridbnb-network
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
# Certbot服务,用于获取和续期SSL证书
certbot:
image: certbot/certbot:latest
container_name: gridbnb-certbot
volumes:
- ./certbot/conf:/etc/letsencrypt:rw # 证书存储目录
- ./certbot/www:/var/www/certbot:rw # webroot目录,用于HTTP-01验证
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
# 注意:entrypoint设置了自动续期循环,每12小时检查一次(Let's Encrypt推荐)
networks:
gridbnb-network:
driver: bridge初始Nginx配置只需处理HTTP(80端口),添加Certbot验证路径。
# GridBNB Trading Bot - Nginx 反向代理配置
# 此配置将外部80端口的请求转发到内部的交易机器人Web服务
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 基本设置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 16M;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# 上游服务器定义
upstream gridbnb_backend {
# 在docker-compose网络中,使用服务名作为主机名
server gridbnb-bot:58181;
keepalive 32;
}
# 主服务器配置
server {
listen 80;
server_name _; # 接受所有域名,您可以改为具体域名
# 日志文件
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# Certbot验证路径
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# 主要代理配置
location / {
proxy_pass http://gridbnb_backend;
proxy_http_version 1.1;
# 代理头设置
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;
# 缓存设置
proxy_cache_bypass $http_upgrade;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 静态文件缓存 (如果有)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
proxy_pass http://gridbnb_backend;
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;
expires 1y;
add_header Cache-Control "public, immutable";
}
# API 路径优化
location /api/ {
proxy_pass http://gridbnb_backend;
proxy_http_version 1.1;
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;
# API 请求不缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
}
docker compose run --rm --entrypoint certbot certbot certonly --webroot --webroot-path /var/www/certbot --dry-run -d <your_domain.com>预期行为: 它会模拟证书请求,使用Let's Encrypt的staging服务器(不会颁发真实证书)。 如果成功:您会看到关于挑战验证(例如通过webroot的HTTP-01)的输出,然后是“The dry run was successful.”。 过程中可能提示输入邮箱和同意条款(因为这是新证书)。
如果成功,移除--dry-run正式申请:
docker compose run --rm --entrypoint certbot certbot certonly --webroot --webroot-path /var/www/certbot -d <your_domain.com>如果成功,您就会看到Successfully received certificate.类似的输出
在修改前,先备份当前nginx.conf,以防万一出错可以恢复。
cp cp ./nginx/nginx.conf ./nginx/nginx.conf.bak使用文本编辑器(如vim、nano或VS Code)打开 ./nginx/nginx.conf 文件。基于您的原始配置,进行以下修改:
-
保留:worker_processes、events、http基本设置(mime.types、log_format、sendfile等)、upstream定义保持不变。
-
修改HTTP server块:将原来的HTTP server改为只处理Certbot验证和重定向到HTTPS。移除原有的代理配置(location /、/api/ 等),因为这些将移到HTTPS块中。
-
添加HTTPS server块:新建一个server块,监听443 ssl,使用证书路径。将原HTTP的代理配置(location /、/api/ 等)复制到这里。
-
注意:确保server_name为您的域名。如果有多个域名,可以添加更多。
完整的最终nginx.conf内容如下,请参考:
# GridBNB Trading Bot - Nginx 反向代理配置
# 此配置将外部80端口的请求转发到内部的交易机器人Web服务
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 基本设置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 16M;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# 上游服务器定义
upstream gridbnb_backend {
# 在docker-compose网络中,使用服务名作为主机名
server gridbnb-bot:58181;
keepalive 32;
}
# HTTP服务器:重定向到HTTPS,并处理Certbot验证
server {
listen 80;
server_name <your_domain.com>; # !!!此处替换为您的域名
# Certbot验证路径(保留,用于续期)
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# 重定向所有请求到HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS服务器:启用SSL,反向代理到后端
server {
listen 443 ssl;
server_name <your_domain.com>; # !!!此处替换为您的域名
# SSL证书路径
ssl_certificate /etc/letsencrypt/live/<your_domain.com>/fullchain.pem; # !!! 此处需要替换您的域名
ssl_certificate_key /etc/letsencrypt/live/<your_domain.com>/privkey.pem; # !!! 此处需要替换您的域名
# 日志文件
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# 主要代理配置
location / {
proxy_pass http://gridbnb_backend;
proxy_http_version 1.1;
# 代理头设置
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;
# 缓存设置
proxy_cache_bypass $http_upgrade;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 静态文件缓存 (如果有)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
proxy_pass http://gridbnb_backend;
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;
expires 1y;
add_header Cache-Control "public, immutable";
}
# API 路径优化
location /api/ {
proxy_pass http://gridbnb_backend;
proxy_http_version 1.1;
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;
# API 请求不缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# 健康检查端点
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
}保存文件后,检查Nginx配置是否语法正确:
docker compose exec nginx nginx -tdocker compose restart nginx