You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Docker容器开启SSH服务的同时完全禁用其互联网访问?

如何在Docker容器开启SSH服务的同时完全禁用其互联网访问?

一、核心问题:开启SSH+彻底禁用容器外网访问

要实现「能SSH进容器但容器完全无外网」,得分两步走:先构建带SSH服务的镜像,再通过网络配置锁死外网访问。

1. 构建带SSH服务的容器镜像

以Ubuntu为例(也可以用更轻量化的Alpine),先做一个包含openssh-server的基础镜像:

FROM ubuntu:latest
# 安装SSH服务并清理缓存
RUN apt-get update && apt-get install -y openssh-server && rm -rf /var/lib/apt/lists/*
# 创建SSH启动所需的目录
RUN mkdir -p /var/run/sshd
# 修改SSH配置,允许root登录(推荐后续换成密钥认证更安全)
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# 设置root密码(替换成你自己的安全密码)
RUN echo 'root:yourSecurePassword123' | chpasswd
# 暴露SSH端口
EXPOSE 22
# 前台启动SSH服务
CMD ["/usr/sbin/sshd", "-D"]

执行构建命令:docker build -t ssh-no-internet .
注意:构建镜像时需要联网下载依赖,但运行容器时会彻底切断外网

2. 运行容器并禁用外网访问

这里有两种可靠方案:

方案A:删除容器默认路由(简单直接)

启动容器时映射SSH端口,赋予容器修改网络的权限,之后删除默认路由切断外网:

# 启动容器,映射主机2222端口到容器22端口,添加网络管理权限
docker run -d -p 2222:22 --name restricted-ssh --cap-add NET_ADMIN ssh-no-internet
# 进入容器删除默认路由,彻底阻断外网访问
docker exec restricted-ssh ip route del default

之后你就能通过ssh root@你的主机IP -p 2222登录容器,此时容器执行ping google.com会完全失败,但和主机的通信不受影响。

方案B:主机端用iptables锁死容器外网(更彻底)

如果担心容器内被篡改网络配置,直接在主机层面用iptables阻止容器的外网流量:

# 先正常启动容器
docker run -d -p 2222:22 --name restricted-ssh ssh-no-internet
# 获取容器的内网IP
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' restricted-ssh)
# 添加iptables规则:允许容器和Docker内网通信,禁止访问外部网络
iptables -A FORWARD -s $CONTAINER_IP ! -d 172.17.0.0/16 -j DROP

172.17.0.0/16是Docker默认桥接网络的网段,如果你用了自定义网络,替换成对应网段即可


二、附加问题:Go服务转发docker exec的终端交互问题

关于你之前用Go服务转发docker exec命令时,nano/vim这类交互式命令无法正常显示的问题,核心是没有分配伪终端(PTY)

解决思路是在调用Docker API时开启PTY并处理双向流:

  1. 用Go的Docker SDK创建ExecConfig时,开启伪终端并配置双向附加:
    execConfig := types.ExecConfig{
        AttachStdin:  true,
        AttachStdout: true,
        AttachStderr: true,
        Tty:          true, // 关键:开启伪终端支持
        Cmd:          []string{"nano"}, // 替换为用户输入的命令
    }
    
  2. 调用Client.ExecAttach获取和容器的连接,再把浏览器的WebSocket(浏览器端实时交互必须用WebSocket)和这个连接的stdin/stdout绑定——把用户的键盘输入传给容器,再把容器的终端输出推回浏览器。

这样就能实现和SSH几乎一致的终端交互体验,支持所有需要终端的命令。

备注:内容来源于stack exchange,提问作者Realman78

火山引擎 最新活动