Skip to content

Instantly share code, notes, and snippets.

@pedrolamas
Created August 18, 2020 19:32
Show Gist options
  • Save pedrolamas/db809a2b9112166da4a2dbf8e3a72ae9 to your computer and use it in GitHub Desktop.
Save pedrolamas/db809a2b9112166da4a2dbf8e3a72ae9 to your computer and use it in GitHub Desktop.
Script to fix Docker iptables on Synology NAS
#!/bin/bash
currentAttempt=0
totalAttempts=10
delay=15
while [ $currentAttempt -lt $totalAttempts ]
do
currentAttempt=$(( $currentAttempt + 1 ))
echo "Attempt $currentAttempt of $totalAttempts..."
result=$(iptables-save)
if [[ $result =~ "-A DOCKER -i docker0 -j RETURN" ]]; then
echo "Docker rules found! Modifying..."
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL ! --dst 127.0.0.0/8 -j DOCKER
echo "Done!"
break
fi
echo "Docker rules not found! Sleeping for $delay seconds..."
sleep $delay
done
@mat926
Copy link

mat926 commented Oct 8, 2023

This doesn't work when trying to access the container from a reverse proxy

@Jabb0
Copy link

Jabb0 commented Nov 30, 2023

Awesome @Maypul thank you!

The change bypassing the synology firewall is understandable and the default docker behaviour.

Other rules added to the FORWARD chain, either manually, or by another iptables-based firewall, are evaluated after the DOCKER-USER and DOCKER chains. This means that if you publish a port through Docker, this port gets published no matter what rules your firewall has configured

https://docs.docker.com/network/packet-filtering-firewalls/#add-iptables-policies-before-dockers-rules

It should only affect ports that you published with docker.

I have my home network on eth0 and another network on eth1. For this reason I only want to accept connections from eth0.

adding the -i eth0 flag does the trick.

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 53 -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -m addrtype --dst-type LOCAL -j DOCKER

@JVT038
Copy link

JVT038 commented Mar 27, 2024

None of these iptables rules have worked for me :(

I'm using a DS918+ and running DSM 7.2.

When I run the iptables script, the X-Forwarded-For IP address becomes the address of my router for some reason. So I don't get the client IP, but the IP of my router.

Does anyone know a fix? I've also tried disabling userland-proxy in the docker daemon, but that didn't work either. Or maybe I did something wrong.

@Aurel004
Copy link

@ben-ba Not sure if we're talking about the same idea. In my nextcloud container it seems to only see the XFF IP if it's an external/public IP. For example here two request:

Client Proxy Service Request appears to be from
10.0.0.2 172.16.0.2 172.30.1.2 172.16.0.2
42.199.8.17 172.16.0.2 172.30.1.2 42.199.8.17
(My local LAN is 10.0.0.0/24)

What I would like to achieve: In the example above the first request should also appear to be from 10.0.0.2 and not how it currently is 172.16.0.2.

Have you got any fix on this ?

@erwinkramer
Copy link

There is a much saner solution for all of this. Just run all your containers on the host network and no additional things are needed. The only 'complex' thing i setup is changing the default ports of the built-in nginx inside a startup script, like @Maypul mentioned, but that is only because i want to use port 443 and port 80 for caddy. So:

sed -i "s/^\( *listen .*\)80/\1$HTTP_PORT/" /usr/syno/share/nginx/*.mustache
sed -i "s/^\( *listen .*\)443/\1$HTTPS_PORT/" /usr/syno/share/nginx/*.mustache

Now in your docker compose file, make sure you:

  • use unique ports for every service
  • specify network_mode: host

It might look like this (the caddy labels are only needed if using caddy of course):

  whoami-public:
    container_name: whoami-public
    image: traefik/whoami
    network_mode: host
    restart: unless-stopped
    environment:
     - WHOAMI_PORT_NUMBER=707
    labels:
      caddy: ${public_protocol}whoami.${public_domain}
      caddy.reverse_proxy: "{{upstreams 707}}"

@jackmaninov
Copy link

jackmaninov commented Jun 30, 2025

I've been having issues similar to this since upgrading to Synology Container Manager 3 and trying to the automatic configuration of proxying with Web Station. While Container Manager could be sending a container's 172.x.x.x address to Web Station, it seems to send 127.0.0.1 and assume a working port forward, which doesn't work.

Since Container Manager 3 it seems you need to add an OUTPUT rule:

iptables -t nat -A OUTPUT -m addrtype --dst-type LOCAL -j DOCKER

Also the test in OP to see whether the docker rules have been applied no longer works, I'm currently using:

if [[ $result =~ "DOCKER-USER" ]]; then

Hope that helps people, I've been pulling my hair out trying to get this to work.

@erwinkramer
Copy link

Thanks @jackmaninov, stumbled on this issue as well. For me, just adding the extra OUTPUT rules works. See my full setup with the change here: erwinkramer/synology-nas-bootstrapper@6066be0#diff-d8aec230d20a8c2cc9b6c6244fb645c874eac419d6095403391d7f15a37a553d (just the change to configuredocker.sh).

I only got this issue after i did a complete reinstall of Container Manager, to 24.0.2-1543. An in-place update (to the same version), that i did before, didn't seem like it required the OUTPUT rework, but i had some other issues so i reinstalled Container Manager, which resulted in this updated behavior as well.

@celticslment
Copy link

Ha tenido problemas similares desde que actualizó Synology Container Manager 3 e intentó configurar automáticamente el proxy con Web Station. Aunque Container Manager podría enviar la dirección 172.xxx de un contenedor a Web Station, parece enviar 127.0.0.1 y supone un reenvío de puerto operativo, lo cual no funciona.

Desde Container Manager 3 parece que es necesario agregar una regla de SALIDA:

iptables -t nat -A OUTPUT -m addrtype --dst-type LOCAL -j DOCKER

Además, la prueba en OP para ver si se han aplicado las reglas de Docker ya no funciona, actualmente estoy usando:

if [[ $result =~ "DOCKER-USER" ]]; then

Espero que esto ayude a la gente, me he estado tirando de los pelos intentando que esto funcione.

Could you pass the complete script? I can't get any of the options listed here to work.

@jackmaninov
Copy link

Could you pass the complete script? I can't get any of the options listed here to work.

#!/bin/bash
currentAttempt=0
totalAttempts=10
delay=15
sleep 60
while [ $currentAttempt -lt $totalAttempts ]
do
	currentAttempt=$(( $currentAttempt + 1 ))
	
	echo "Attempt $currentAttempt of $totalAttempts..."
	
	result=$(iptables-save)

	if [[ $result =~ "DOCKER-USER" ]]; then
		echo "Docker rules found! Modifying..."
		
		iptables -t nat -A PREROUTING ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
                #iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL ! --dst 127.0.0.0/8 -j DOCKER  # seems unnecessary
                iptables -t nat -A OUTPUT -m addrtype --dst-type LOCAL -j DOCKER
		
		echo "Done!"
		
		break
	fi
	
	echo "Docker rules not found! Sleeping for $delay seconds..."
	
	sleep $delay
done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment