如何禁止通过HTTP直接访问Debian服务器上的Docker容器?
问题
我在Debian服务器上搭建了多个Docker容器,每个容器对应独立端口。服务器IP为160.160.160.160,绑定域名example160.com,两个容器分别运行在5500和6600端口。
已配置Nginx反向代理,可通过子域名app5500.example160.com、app6600.example160.com访问应用,同时配置了HTTP转HTTPS规则(仅http://app5500.example160.com访问时生效)。但目前仍可通过http://www.example160.com:5500、http://160.160.160.160:5500这类地址直接访问容器,希望仅允许通过https://app5500.example160.com访问。
尝试过添加额外Nginx配置重定向其他子域名,但未生效;也曾配置iptables和nftables防火墙,也没解决问题,特此求助。
现有反向代理配置
server { listen 443 ssl; # managed by Certbot server_name app5500.example160.com; location / { proxy_pass https://127.0.0.1:80/; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Accept-Encoding gzip; } ssl_certificate /etc/letsencrypt/live/example160.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/example160.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { listen 80; server_name app5500.example160.com; if ($host = app5500.example160.com) { return 301 https://$host$request_uri; } # managed by Certbot return 404; # managed by Certbot }
尝试过的无效配置
server { listen 443 ssl; server_name *.example160.com; if ($host !~ ^example160\.com$) { return 301 https://example160.com$request_uri; } ssl_certificate /etc/letsencrypt/live/example160.com-0001/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example160.com-0001/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; return 404; } server { listen 80 default_server; server_name *.example160.com; return 301 https://example160.com$request_uri; }
解决方案
1. 限制Docker容器仅绑定本地回环地址
直接通过IP:端口访问容器的核心原因是容器端口绑定到了服务器的公网IP(0.0.0.0),导致外部可以直接访问。修改容器启动配置,将端口映射改为仅绑定127.0.0.1:
- 单容器启动命令示例:
docker run -d -p 127.0.0.1:5500:容器内部端口 你的镜像名 - docker-compose.yml示例:
services: app5500: image: 你的镜像名 ports: - "127.0.0.1:5500:容器内部端口"
修改后容器端口仅对本地(Nginx所在服务器)开放,外部无法直接通过IP:5500访问。
2. 优化Nginx配置,拦截非法域名访问
添加默认服务器块,处理所有未匹配到指定子域名的请求(包括IP访问、其他子域名访问):
新增HTTP默认服务器(拦截80端口非法请求)
server { listen 80 default_server; server_name _; # 匹配所有未指定的主机名 # 仅允许app5500.example160.com的HTTP请求跳转HTTPS,其他直接返回404 if ($host != 'app5500.example160.com') { return 404; } }
新增HTTPS默认服务器(拦截443端口非法请求)
server { listen 443 ssl default_server; server_name _; # 使用主域名证书(确保证书覆盖相关域名) ssl_certificate /etc/letsencrypt/live/example160.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example160.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # 仅允许指定子域名访问,其他返回404 if ($host != 'app5500.example160.com') { return 404; } }
补充app6600的HTTPS配置(若需要)
如果app6600也需通过指定子域名访问,添加对应服务器块:
server { listen 443 ssl; server_name app6600.example160.com; location / { proxy_pass http://127.0.0.1:6600/; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Accept-Encoding gzip; } ssl_certificate /etc/letsencrypt/live/example160.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example160.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } server { listen 80; server_name app6600.example160.com; return 301 https://$host$request_uri; }
3. 防火墙加固(可选)
确保仅开放80、443端口给外部,关闭5500、6600端口的公网访问:
iptables命令:
# 允许80、443端口 iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 拒绝5500、6600端口外部访问 iptables -A INPUT -p tcp --dport 5500 -j DROP iptables -A INPUT -p tcp --dport 6600 -j DROP # 保存规则 iptables-save > /etc/iptables/rules.v4nftables配置(/etc/nftables.conf):
table inet filter { chain input { type filter hook input priority 0; policy drop; # 允许本地回环 iif lo accept # 允许已建立的连接 ct state established,related accept # 允许80、443端口 tcp dport {80, 443} accept # 拒绝5500、6600端口 tcp dport {5500, 6600} drop } }重启nftables服务:
systemctl restart nftables
验证配置
- 重启Nginx:
systemctl restart nginx - 重启Docker容器(若修改了端口映射):
docker restart 容器名 - 测试访问:
- 访问https://app5500.example160.com:正常打开
- 访问http://160.160.160.160:5500、http://www.example160.com:5500:无法访问或返回404
- 访问其他子域名如https://test.example160.com:返回404
内容的提问来源于stack exchange,提问作者Neji Soltani

