You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何禁止通过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.v4
    
  • nftables配置(/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

验证配置

  1. 重启Nginx:systemctl restart nginx
  2. 重启Docker容器(若修改了端口映射):docker restart 容器名
  3. 测试访问:
    • 访问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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 23:49:51