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

如何通过VPN安全远程访问Docker容器并保障内部通信

问题与解决方案

问题背景

生产服务器上部署了Docker环境,希望从本地机器通过WireGuard访问Postgres和Redis容器,但将这两个容器设置为network_mode: service:wireguard后,导致应用等其他容器无法与它们通信。

目标

  • 通过VPN安全访问Postgres和Redis,不将其暴露给公网;
  • 允许应用及其他容器正常连接Postgres和Redis。

解决方案:调整网络配置,分离容器网络与VPN转发

核心思路是让Postgres和Redis留在Docker的backend桥接网络中,仅监听该网络的内部IP,同时通过WireGuard容器做端口转发,只允许VPN子网的流量访问这两个服务,既保证本地VPN访问,又不影响容器间通信。

修改后的docker-compose.yml配置

services:
  wireguard:
    image: ghcr.io/linuxserver/wireguard
    container_name: wireguard
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=UTC
      - SERVER_URL=my_ip_or_domain 
      - SERVER_PORT=51820
      - PEERS=5
      - PEERDNS=auto
      - ALLOWEDIPS=10.0.0.0/24
    volumes:
      - ./config/wireguard:/config
      - /lib/modules:/lib/modules
    ports:
      - "51820:51820/udp"
      # 仅将Postgres和Redis端口转发到WireGuard容器的内部IP,仅VPN子网可访问
      - "10.13.13.1:5432:5432"
      - "10.13.13.1:6379:6379"
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    networks:
      backend:
        # 给WireGuard容器分配固定IP,方便端口转发配置
        ipv4_address: 10.13.13.1
    restart: unless-stopped

  app:
    image: myimage:latest
    container_name: backend_app
    depends_on:
      - redis
      - postgres
    networks:
      - backend
    restart: unless-stopped

  postgres:
    image: postgres:latest
    environment:
      POSTGRES_DB: '${DB_DATABASE}'
      POSTGRES_USER: '${DB_USERNAME}'
      POSTGRES_PASSWORD: '${DB_PASSWORD}'
      # 让Postgres仅监听backend网络的IP,避免暴露到其他网络
      POSTGRES_LISTEN_ADDRESSES: 10.13.13.2
    volumes:
      - 'backend-pgsql:/var/lib/postgresql/data'
    networks:
      backend:
        ipv4_address: 10.13.13.2
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME}"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped

  redis:
    image: redis:alpine
    volumes:
      - 'backend-redis:/data'
    # 让Redis仅监听backend网络的IP
    command: redis-server --bind 10.13.13.3
    networks:
      backend:
        ipv4_address: 10.13.13.3
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 5s
      retries: 3
    restart: unless-stopped

networks:
  backend:
    driver: bridge
    # 给backend网络指定固定子网,确保容器IP稳定
    ipam:
      config:
        - subnet: 10.13.13.0/24

volumes:
  backend-pgsql:
    driver: local
  backend-redis:
    driver: local

关键改动说明

  1. 移除Postgres/Redis的network_mode: service:wireguard,将它们放回backend网络,并分配固定内部IP;
  2. 限制Postgres/Redis的监听地址:
    • Postgres通过POSTGRES_LISTEN_ADDRESSES环境变量指定仅监听自身在backend网络的IP;
    • Redis通过启动命令--bind参数指定仅监听自身在backend网络的IP;
  3. WireGuard容器配置固定IP,并添加端口转发规则,仅将Postgres和Redis的端口绑定到WireGuard容器的内部IP(而非主机公网IP);
  4. 指定backend网络的固定子网,确保容器IP稳定。

应用配置无需修改

原应用配置可以继续使用容器名(postgres/redis)作为连接地址,因为它们在同一个backend网络中,Docker DNS会自动解析到对应容器的IP:

DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=qa
DB_USERNAME=root

REDIS_CLIENT=predis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

本地VPN访问方式

连接WireGuard VPN后,直接使用WireGuard容器的内部IP(10.13.13.1)作为Postgres和Redis的主机地址,即可访问这两个服务。

其他可选方案

  • 方案1:使用WireGuard客户端模式容器:部署单独的WireGuard客户端容器,让Postgres/Redis连接到该容器的网络,同时让客户端容器加入backend网络,容器间通过backend网络通信,本地通过WireGuard服务器连接客户端所在VPN子网访问服务。
  • 方案2:使用Docker macvlan网络:创建macvlan网络,让WireGuard和Postgres/Redis都加入该网络,配置macvlan与主机网络的路由,适合复杂网络场景,但需要主机网卡支持,配置相对复杂。

内容的提问来源于stack exchange,提问作者Wushu06

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:52:48