DB-유

Docker Networking on Synology: Bridge vs Host

· synology, docker, networking

Most Docker problems I get asked about on a Synology turn out to be networking problems in disguise. A container works from the NAS but not from the LAN, two containers can't see each other, a service insists on port 80 that DSM already owns, or a DNS server sees every client as 172.17.0.1. It all comes down to the network mode, and the Docker package GUI squeezes that into one checkbox that hides three very different setups.

Here's bridge, host and macvlan on DSM 6.2, in terms of what actually happens to packets, when I pick each, and how to set up the two the GUI doesn't fully expose. It assumes SSH access with an administrator account and some comfort with docker-compose.

Bridge mode

This is the default and what the GUI uses when "Use the same network as Docker Host" is unticked. Docker creates a virtual switch docker0 with the subnet 172.17.0.0/16; every container gets an address on it and the NAS does NAT between that subnet and the LAN. A port mapping such as 8080:80 is an iptables rule forwarding NAS port 8080 to the container's port 80.

sudo docker network ls
sudo docker network inspect bridge
sudo iptables -t nat -L DOCKER -n

Consequences:

  • Containers are reachable from the LAN only on the ports you publish, on the NAS's IP.
  • A published port must be free on the NAS. 80, 443, 5000, 5001, 22 and 3306 (if MariaDB is installed) are taken by DSM.
  • Containers on the default bridge reach each other by IP but not by name. On a user-defined bridge, which is what docker-compose creates for each project, they reach each other by service name.
  • Inbound connections appear to the container as coming from the bridge gateway, so the real client IP is lost unless the application reads X-Forwarded-For from a proxy.

I use bridge for web applications behind DSM's reverse proxy, for databases that only other containers or a few LAN hosts use, and for anything where you are happy to pick the host port.

Host mode

Ticking "Use the same network as Docker Host" or network_mode: host removes the network namespace: the container shares the NAS's interfaces and binds ports directly on eth0. There is no port mapping; whatever port the application listens on is the port on the NAS.

version: '2'
services:
  netdata:
    image: netdata/netdata
    network_mode: host
    restart: unless-stopped

Consequences:

  • Real client IPs are visible to the application.
  • Slightly better throughput, since there is no NAT.
  • Port conflicts with DSM are unavoidable if the application wants 80 or 443, and you cannot remap them.
  • Two containers cannot both use host mode if they want the same port.

Use host mode for monitoring agents that need to see the real interfaces, for applications that use many dynamic ports (media servers with DLNA discovery), and for anything that needs to receive broadcast or multicast traffic.

Macvlan: a real LAN address for the container

Macvlan gives a container its own MAC and IP address on the physical LAN, as if it were a separate machine plugged into the switch. This is the answer for Pi-hole or a reverse proxy that must own ports 80 and 443 without fighting DSM, and for anything that needs to be a first-class device on the network.

The Docker GUI cannot create a macvlan network; it must be done once over SSH.

Creating the macvlan network

Pick a small range of addresses within the LAN that the router's DHCP will never assign. Here the LAN is 10.20.30.0/24, the gateway 10.20.30.1, and I reserve 10.20.30.240 to 10.20.30.247:

sudo docker network create -d macvlan \
  --subnet=10.20.30.0/24 \
  --gateway=10.20.30.1 \
  --ip-range=10.20.30.240/29 \
  -o parent=eth0 \
  lan-macvlan

eth0 is LAN 1; on a bonded interface use bond0, on a VLAN sub-interface eth0.20. Check the name with ip link.

Attaching a container with a fixed address

version: '2'
services:
  pihole:
    image: pihole/pihole
    container_name: pihole
    restart: unless-stopped
    networks:
      lan-macvlan:
        ipv4_address: 10.20.30.241
    environment:
      TZ: Europe/Berlin
      WEBPASSWORD: choose-a-password
    volumes:
      - /volume1/docker/pihole/etc-pihole:/etc/pihole
      - /volume1/docker/pihole/etc-dnsmasq.d:/etc/dnsmasq.d
networks:
  lan-macvlan:
    external: true

No port section at all; the container listens on 53 and 80 at 10.20.30.241 directly, and DSM keeps its own 80 on 10.20.30.5.

Letting the NAS talk to the macvlan container

The annoying limitation of macvlan is that the host cannot reach its own macvlan containers. Every other LAN device can. If the NAS itself needs to use the Pi-hole as its DNS, add a macvlan shim interface on the host:

sudo ip link add macvlan-shim link eth0 type macvlan mode bridge
sudo ip addr add 10.20.30.247/32 dev macvlan-shim
sudo ip link set macvlan-shim up
sudo ip route add 10.20.30.240/29 dev macvlan-shim

These commands do not survive a reboot; put them in a Task Scheduler "Triggered Task" on boot-up, running as root.

Checking the macvlan container

sudo docker inspect pihole --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
ping -c 3 10.20.30.241        # from a LAN PC, works; from the NAS, only with the shim
dig @10.20.30.241 www.synology.com +short
arp -a | grep 10.20.30.241    # from a LAN PC, shows a MAC starting 02:42

The arp check confirms the switch sees the container as its own device.

Things that have bitten me

  • docker: Error response from daemon: network lan-macvlan not found after a DSM reboot. The Docker package sometimes loses user-defined networks on package updates. Recreate it with the same command; containers referencing it by name reconnect.
  • Bridge container unreachable from the LAN while curl localhost:8080 on the NAS works. The DSM firewall is blocking the published port; add a rule under Control Panel → Security → Firewall. Docker's iptables rules sit behind DSM's.
  • Two docker-compose projects cannot talk to each other. Each project gets its own bridge network. Put both services in the same compose file, or declare a shared external network and attach both to it.
  • Macvlan container has no internet access. The gateway in docker network create is wrong, or the switch port has port security limiting MAC addresses. Check sudo docker exec pihole ip route and ask the network team about MAC limits.

Bridge by default, host when the app truly needs the interfaces, macvlan when it must own a well-known port. Knowing which of the three a container is in explains nearly every "works from here but not from there" report I get.