skip to Main Content

I have an ARM64-based Synology NAS device and have been trying to set up Docker on it using the instructions found here:

Can I install Docker on arm8 based Synology Nas

However, the fact that I can’t use the default bridge network mode but instead have to use host mode (network_mode=host) is preventing me from doing some things that I’d like to do. In the aforementioned thread user P Leo writes:

Please note, you need to set storage drive vfs, iptables off, bridge
off due to a Linux kernel problem. And you need to run docker
container with –network=host mode. It is not usual, but it is
necessary due to Synology NAS kernel limitations.

I was wondering if anyone could shed more light on this apparent limitation? Based on other Synology- and Docker-related discussions online, it seems that it doesn’t affect some users. Is the issue perhaps limited to ARM-based devices or specific Linux kernel versions (my device has 4.4.180+)? And most importantly, is there really no way around it?

Thanks in advance for any help!

2

Answers


  1. The answer is Yes that you Can use completely docker functionality on ARM-based Synology NAS, including bridge functionality.

    Before you use it, you need complete the missed .ko driver files for the Synology NAS linux kernel.

    You can follow the steps in https://www.v2ex.com/t/850768#reply2 to complete all missed .ko files. Then you can run Docker with full functionality on ARM-based Synology NAS.

    Login or Signup to reply.
  2. I’ve done this recently on a DS218 that has an arm64 (RTD1296) CPU. It’s a bit involved but doable.

    Start Docker in bridge Mode

    First thing, check if your NAS has the necessary kernel modules in /usr/lib/modules. Mine did, so load them in this order:

      sudo insmod /usr/lib/modules/veth.ko
      sudo insmod /usr/lib/modules/stp.ko
      sudo insmod /usr/lib/modules/tun.ko
    # sudo insmod /usr/lib/modules/nf_defrag_ipv4.ko # Already loaded for me
    # sudo insmod /usr/lib/modules/nf_conntrack.ko
    # sudo insmod /usr/lib/modules/x_tables.ko
      sudo insmod /usr/lib/modules/xt_TCPMSS.ko
    # sudo insmod /usr/lib/modules/xt_recent.ko
      sudo insmod /usr/lib/modules/xt_NFQUEUE.ko
      sudo insmod /usr/lib/modules/xt_mark.ko
    # sudo insmod /usr/lib/modules/xt_mac.ko
    # sudo insmod /usr/lib/modules/xt_limit.ko
    # sudo insmod /usr/lib/modules/xt_iprange.ko
    # sudo insmod /usr/lib/modules/xt_geoip.ko
      sudo insmod /usr/lib/modules/xt_addrtype.ko
      sudo insmod /usr/lib/modules/xt_conntrack.ko
    # sudo insmod /usr/lib/modules/xt_LOG.ko
      sudo insmod /usr/lib/modules/bridge.ko
      sudo insmod /usr/lib/modules/br_netfilter.ko
    # sudo insmod /usr/lib/modules/xt_state.ko
    # sudo insmod /usr/lib/modules/xt_tcpudp.ko
    # sudo insmod /usr/lib/modules/xt_multiport.ko
      sudo insmod /usr/lib/modules/nf_nat.ko
    # sudo insmod /usr/lib/modules/nf_conntrack_ipv4.ko
    # sudo insmod /usr/lib/modules/ip_tables.ko
      sudo insmod /usr/lib/modules/nf_nat_redirect.ko
      sudo insmod /usr/lib/modules/xt_REDIRECT.ko
      sudo insmod /usr/lib/modules/xt_nat.ko
      sudo insmod /usr/lib/modules/nf_nat_ipv4.ko
      sudo insmod /usr/lib/modules/nf_nat_masquerade_ipv4.ko
      sudo insmod /usr/lib/modules/ipt_MASQUERADE.ko
    # sudo insmod /usr/lib/modules/iptable_filter.ko
      sudo insmod /usr/lib/modules/iptable_nat.ko
    

    (If you see a File Exists error, ignore it; it just means the module has already been loaded.)

    Then check if iptables can match by addrtype or conntrack since dockerd needs both.

    iptables -m addrtype -h
    iptables -m conntrack -h
    

    If you see an error such as No such file or directory, you have work to do. You can either install a version of iptables that’s not crippled from Entware (opkg install iptables), or you can compile the missing libs yourself. I did the latter on my Mac:

    % docker run --name=ubuntu -it --rm --platform linux/arm64 --entrypoint bash ubuntu:latest
    % apt-get update && apt-get install build-essential bc bison flex vim wget xz-utils
    % mkdir /syno && cd /syno
    ### Note: version 1.6.0 was shipped with my NAS
    % wget https://www.netfilter.org/projects/iptables/files/iptables-1.6.0.tar.bz2
    ### Note: also needed these dependent packages
    % wget https://www.netfilter.org/projects/libnftnl/files/libnftnl-1.0.5.tar.bz2
    % wget https://www.netfilter.org/projects/libmnl/files/libmnl-1.0.3.tar.bz2
    % tar -xjf *.tar.bz2
    % cd iptables-1.6.0
    % cp ../libnftnl-1.0.5/include/libnftnl include/
    % cp ../libmnl-1.0.3/include/libmnl include/
    % ./configure --host=arm-linux-gnueabi --target=arm-linux-gnueabi --prefix=/syno
    % make
    % find /syno -name libxt_*so
    

    The compile failed for me, but it produced the 2 libs libxt_addrtype.so and libxt_conntrack.so I needed. Copy them to /usr/lib/iptables/ on your NAS, the 2 commands above should run without errors.

    And now dockerd should be able to start successfully with bridge network:

    sudo cat <<EOF >/etc/docker/daemon.json
    {
        "storage-driver": "vfs",
        "bip": "172.16.0.1/16",
        "default-gateway": "172.16.0.254"
    }
    EOF
    sudo /bin/dockerd &
    

    Turn on IP Forwarding and Configure Firewall

    To be able to communicate with your containers from your LAN, you also need to do these to allow IP forwarding:

    # Turn on IP forwarding
    sudo sysctl -w net.ipv4.ip_forward=1
    sudo sysctl -w net.ipv6.conf.all.forwarding=1
    sudo iptables -P FORWARD ACCEPT
    # Allow containers to access Docker socket
    sudo chmod 666 /var/run/docker.sock
    

    And finally, open up your firewall to allow access to the ports. Assuming you have -p 8080:80 for a container, you’ll need to open port 8080 for your LAN the NAS is in (eg. 192.168.0.0/24).

    Configure a Proxy

    With the above though, what I found was, if I ran a container with published ports, I still could only reach the server via localhost, but not via the LAN IP of my NAS.

    sudo docker run 
        --name=nginx-test 
        --rm 
        --network=bridge 
        -e PUID=`id -u $USER` 
        -e PGID=`id -g $USER` 
        -p 8080:80 
        -v /volume1/docker/nginx:/usr/share/nginx/html:ro 
        -v /dev:/dev 
        nginx:latest
    
    curl localhost:8080    # This succeeded
    curl 192.168.0.10:8080 # This timed out
    

    Docker was supposed to take care of this for me, but somehow it didn’t.

    So I needed a proxy to forward packets (TCP in addition to HTTP/S, in my use case) between 192.168.0.10:8080 and localhost:8080. I opted to use nginx because I couldn’t get either iptables or docker-proxy to work, but I had to change my LAN access to a new port, ie. 192.168.0.10:8081.

    opkg install nginx # Needed v1.9, the one shipped was too old
    cat <<EOF >/opt/etc/nginx/nginx.conf
    user nobody users;
    stream {
        upstream server_8080 {
            server localhost:8080;
        }
        server {
            listen 8081;
            proxy_pass server_8080;
        }
    }
    sudo /opt/etc/init.d/S80nginx start
    

    Finally after also changing the open port in firewall to 8081, curl 192.168.0.10:8081 worked.

    PS. If someone could tell me why iptables or docker-proxy didn’t forward ports between localhost and my LAN IP, I’ll appreciate it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search