{{tag>linux docker image container openvpn "docker compose" wireguard macvlan nftables}} ======Docker Deluge Image / Service====== I want a torrent service that uses a VPN and is set-up to block non VPN WAN (internet) access. On my virtual machine implementation of this I used the following 3 packages: deluge (deluged with deluge-web), openvpn and nftables. I have used both iptables and nftables and find nftables is definitely more elegant to use. As far as I can tell there is not a Docker image that will meet my needs. I have been successfully been running this in a container on my home server since early 2023. This replaced the a similar setup that have I been operating since about 2017 on a virtual machine using Linux KVM/Libvirt/QEMU. =====dockerfile===== ++++Dockerfile| FROM alpine:latest ADD https://github.com/just-containers/s6-overlay/releases/download/v3.1.3.0/s6-overlay-noarch.tar.xz /tmp RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz ADD https://github.com/just-containers/s6-overlay/releases/download/v3.1.3.0/s6-overlay-x86_64.tar.xz /tmp RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz ENTRYPOINT ["/init"] RUN apk update && \ apk --no-cache add openvpn deluge nftables &&\ apk upgrade #RUN apk add --no-cache tini openrc COPY privatvpn.conf /etc/openvpn/privatvpn.conf COPY privatvpn.login /etc/openvpn/privatvpn.login COPY pre_start_tun.sh /etc/openvpn/ COPY user/* /etc/s6-overlay/s6-rc.d/user/contents.d #COPY user/pre_start_tun /etc/s6-overlay/s6-rc.d/user/contents.d/ #COPY user/pre_start_nft /etc/s6-overlay/s6-rc.d/user/contents.d/ #COPY user/privatvpn /etc/s6-overlay/s6-rc.d/user/contents.d/ #COPY user/deluged /etc/s6-overlay/s6-rc.d/user/contents.d #COPY user/delugeweb /etc/s6-overlay/s6-rc.d/user/contents.d COPY s6-rc.d /etc/s6-overlay/s6-rc.d/ COPY nftables.conf /etc/ EXPOSE 8112/tcp #ENV PYTHON_EGG_CACHE "/app/.cache/Python-Eggs" #CMD ["nft", "-f", "/etc/nftables.conf","&&","openvpn","--config","/etc/openvpn/ovpn_file.conf","--daemon","deluged","-d"] Notes: - The Alpine package deluge includes deluged and deluge-web. - Alpine uses busybox for most the Linux built-in commands. The main init and services control needs to be added with packages tini and openrc. - I have swapped to using s6 init system ++++ *''docker build -t deluge-openvpn-nftables .'' - to create the image deluge-openvpn-nftables *''docker run -it -p 8112:8112 --name deluge deluge-openvpn-nftables /bin/sh'' - to run the docker image deluge-openvpn-nftables as a container called deluge, with port 8112 passed through, the deluge web interface. *Inside the container shell the deluge system can be started with the command ''deluge web'' It looks like I need to write an openrc script to allow the application to be controlled by the build in system. ---- =====VPN setup including nftable force to anonymize WAN usage===== I use 2 forms of vpn (virtual private network) on my home server. - VPN to gain remote secure private access to my home LAN from the WAN (internet). //This is where I describe this [[https://wiki.kptree.net/doku.php?id=linux_router:wireguard|Wireguard VPN access from WAN to LAN]]//. - VPN to anonymize my public internet access, making it more difficult for others to track my online behavior. //This is the one I am describing here.// -There are some other potential benefits with this style of VPN usage, e.g. greater privacy and ability to have ip address based on different geographic location. ====VPN Provider==== I am currently using [[https://privatevpn.com/|PrivateVPN]] as my public VPN provider. They use openVPN for access, with a login configuration. I noticed that they recently now also have the capability to use up to 8 Wireguard configurations. After logging in to their website the Wireguard configurations can be found here [[https://privatevpn.com/control-panel|PrivateVPN config panel]]. ====OpenVPN setup==== Most of the notes below were taken discovering and implementing the Docker usage of openvpn with the s6 init system. That being said there my be some handy bits in there, ++++tldr;| *''%%docker run -it -p 8112:8112 --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' *The --cap-add=NET_ADMIN is require remove tun permission error when attempting to run openvpn. This setting allows docker networking to perform routing, which is required for vpn operation. *openvpn does not seem to work well with "standard" port mapping option of Docker. The VPN performs unreliably with the nftables and the map port to the local web interface simply stops working. It seems to work much more reliably in host mode ''%%docker run -it --network host --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' *The docker host network option also has problems the entire host network is placed on the VPN! Also it stops working when the tun is stopped and need to be reset! so now trying ++macvlan option| docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --ip-range=192.168.1.95/30 \ --gateway=192.168.1.1 \ -o parent=enp1s0 macnet1 ++ * In order to find the ip address of the vpn server I just ping the vpn access server and ensure this address is open for output on the firewall, details: *''ping au-per.pvdata.host'' * in ''/etc/nftables.conf'' under under output chain: *''oifname $lan ip daddr 103.231.89.219 counter accept #Host: au-per.pvdata.host'' * where $lan is set to lan interface, e.g. enp1s0 * ''%%docker run -it --network macnet1 --ip=192.168.1.98 --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' * When running nftables to stop leakage of vpn it was found that the docker networking cause failure. Docker use loop address 127.0.0.11 to resolve its dns queries and then refers to the nominated local dns. See ''/etc/resolv.conf''. The docker documentation states that the user should not directly modify the resolv.conf file as it may adversely affect docker performance. As the openvpn program rewrites resolv.conf anyway I decided to do the same in a oneshot to point dns directly. I subsequently remembered the basics of UNIX the /etc/hosts file, this is the lowest level DNS on every machine. I simply added the relevant Private VPN end hosts files in here and this worked a beaut. * Need to manually create ++/dev/net/tun| #!/bin/sh mkdir -p /dev/net mknod /dev/net/tun c 10 200 chmod 660 /dev/net/tun echo "103.231.89.219 au-mel.pvdata.host" >> /etc/hosts #This adds a PrivatVPN host to the host DNS echo "103.231.88.203 au-mel.pvdata.host" >> /etc/hosts #This adds a PrivatVPN host to the host DNS echo "143.244.63.96 au-syd.pvdata.host" >> /etc/hosts #This adds a PrivatVPN host to the host DNS echo "143.244.33.81 sg-sin.pvdata.host" >> /etc/hosts #This adds a PrivatVPN host to the host DNS /usr/sbin/openvpn /etc/openvpn/privatvpn.conf & #This runs the openvpn program in background using nominated configuration file ++ see [[https://serverfault.com/questions/1003011/openvpn-error-cannot-open-tun-tap-dev-dev-net-tun-no-such-file-or-directory|OpenVPN - ERROR: Cannot open TUN/TAP dev /dev/net/tun: No such file or directory (errno=2)]] *Inside container command to run ''/usr/sbin/openvpn /etc/openvpn/privatvpn.conf'', add & to free up terminal *To check nftables ''nft list table ip firewall'' To start deluged up directly in container ''%%/usr/bin/python3 /usr/bin/deluged --port=58846 --config=/root/.config/deluge/ &%%'' however better using using ''/usr/bin/deluged -d'' ++++ *To check external IP ''wget -qO - icanhazip.com'', reference from [[https://linuxnightly.com/check-external-ip-from-linux-command-line/|Check External IP From Linux Command Line]] *OpenVPN [[https://openvpn.net/community-resources/how-to/|2x HOW TO]] Look at troubleshooting =====docker external volumes===== There are 2 type of volume needs in this set up. - Deluge configuration directory - I usually like to store my live application configuration files with the docker image / container setup - Deluge file storage - download directories (working directories) - actual download working directory - torrent file storage directory directory - completed directory where finish torrent files are stored (longer term storage directories) ====deluge configuration files==== Next set is to get the deluge configuration files outside the ephemeral container storage to some permanent storage: The -v /mnt/docker_store/media/.config:/root/.config/deluge/ make Docker map the external directory ''/mnt/docker_store/media/'' on to the internal directory, ''/root/.config/deluge/''. ''%%docker run -it -v /mnt/docker_store/media/.config:/root/.config/deluge/ --network macnet1 --ip=192.168.1.98 --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' ====deluge working file storage==== Clearly deluge files need to be stored outside the docker ephemeral container storage to some permanent storage. I have nfs setup on the host which I will setup relevant sub-directories as volumes on the deluge container for storage. The docker web application allows the store to be selected, however the storage options need to setup to allow function. I will use the container directory ''/app'' to store these sub-directories. * ''-v /mnt/deluge:/app/deluge'' ++|the ''/mnt/deluge'' directory has the sub-directories ''Downloads'' and ''torrent'' which will show up as sub-directories under ''/app/deluge'' ++ * ''-v /mnt/disk2/Media/Temp/Complete:/app/Complete'' The final docker run command is now: ''%%docker run -it -v /mnt/docker_store/media/.config:/root/.config/deluge/ -v /mnt/deluge:/app/deluge -v /mnt/disk2/Media/Temp/Complete:/app/Complete --network macnet1 --ip=192.168.1.98 --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' ====Docker nfs volume==== After a couple of minor syntax typos I got the basic docker nfs volume working, but when I tried to get 2 volumes set up it was wonky. To date I have not further investigated why. ++++tldr;| Next is access to main NAS storage via NFS: Basic NFS volume crate command, assume that NFS server is running. docker volume create --driver local \ --opt type=nfs \ --opt o=addr=[ip-address],rw \ --opt device=:[path-to-directory] \ [volume-name] For deluge working directory: docker volume create --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.10,rw \ --opt device=:deluge \ deluge For deluge completed working directory: docker volume create --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.10,rw \ --opt device=:disk2/Media/Temp/Complete \ Complete ''%%docker run -it -v /mnt/docker_store/media/.config:/root/.config/deluge/ --mount 'type=volume,source=nfsvolume,target=/app/Complete,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/disk2/Media/Temp/Complete,"volume-opt=o=addr=192.168.1.10,rw,nfsvers=4,async"' --mount 'type=volume,source=nfsvolume,target=/app/deluge,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/deluge,"volume-opt=o=addr=192.168.1.10,rw,nfsvers=4,async"' --network macnet1 --ip=192.168.1.98 --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' ''%%docker run -it -v /mnt/docker_store/media/.config:/root/.config/deluge/ --mount 'type=volume,source=nfsvolume,target=/app/Complete,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/disk2/Media/Temp/Complete,"volume-opt=o=addr=192.168.1.10,rw,nfsvers=4,async"' --network macnet1 --ip=192.168.1.98 --cap-add=NET_ADMIN --name alpine deluge-openvpn-nftables /bin/sh%%'' ++++ =====Docker network===== As described in the vpn section [[https://wiki.kptree.net/doku.php?id=docker_notes:docker-deluge#openvpn_setup|openvpn setup]], I decided to go with the docker macvlan network setup. This needs to be separately created and can then be called up when the container is run. A static ip address can be assigned when run. docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --ip-range=192.168.1.95/30 \ --gateway=192.168.1.1 \ -o parent=enp1s0 macnet1 *[[https://docs.docker.com/network/network-tutorial-macvlan/|Docker Docs: Networking using a macvlan network]] *[[https://docs.docker.com/compose/networking/|Docker Docs : Networking in Compose]] *[[https://gdevillele.github.io/engine/userguide/networking/get-started-macvlan/|Macvlan Network Driver]] *[[https://stackoverflow.com/questions/49600665/docker-macvlan-network-inside-container-is-not-reaching-to-its-own-host|Docker Macvlan network inside container is not reaching to its own host]] *[[https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/|Using Docker macvlan networks]] *[[https://ipwithease.com/macvlan-vs-ipvlan-understand-the-difference/|MacVLAN vs IPvlan: Understand the difference]] =====Compose file===== My final docker run command was ''docker run -it -v /mnt/docker_store/media/.config:/app/.config/deluge/ -v /mnt/docker_store/media/.cache/Python-Eggs:/app/.cache/Python-Eggs -v /mnt/deluge:/app/deluge -v /mnt/disk2/Media/Temp/Complete:/app/Complete --network macnet1 --ip=192.168.1.98 --cap-add=NET_ADMIN --name deluge deluge-openvpn-nftables /bin/sh'' which I had to convert to docker-compose yml script. The docker build command to build the image was ''docker build -t deluge-openvpn-nftables .'' The compose.yml file is: version: '3.9' services: deluge: build: ./ image: deluge-openvpn-nftables:latest tty: true stdin_open: true container_name: deluge restart: 'unless-stopped' # always | no | on-failure [:5 (max-retries)] volumes: - '/mnt/docker_store/media/.config:/app/.config/deluge/' - '/mnt/docker_store/media/.cache/Python-Eggs:/app/.cache/Python-Eggs' - '/mnt/deluge:/app/deluge' - '/mnt/disk2/Media/Temp/Complete:/app/Complete' networks: macnet1: ipv4_address: 192.168.1.98 cap_add: - NET_ADMIN command: /bin/sh networks: macnet1: external: true Some basic docker compose commands: *''docker-compose up -d'' to start up the container *''%%docker-compose up -d --build%%'' to start up and force build the container image first *''docker-compose down'' to stop and remove the container *''docker-compose stop'' to stop the container *''docker-compose start'' to start the container Notes: -The ''cap_add: NET_ADMIN'' is required to allow the container network to allow routing functionality. This is required for the openvpn to operate. -As I run all my one-shots and longruns using s6 init, this is no command that is running to keep the container open (perhaps a poor explanation) The statement ''command: /bin/sh'' not only keeps the container open it also allows me to shell into it via docker, ''docker attach servicename''. There are 2 ways to get out, use ''exit'' in the shell which attempts to exit, or type control p then control q. (As I am not running an ssh server in the container, ssh cannot be used.) =====Environment Variables into Docker===== I need to work on this one more. It did not seem to work well for me in attempts to date. I tried again in mailserver setup also to no avail. ''S6_KEEP_ENV'' (default = 0): if set, then environment is not reset and whole supervision tree sees original set of env vars. It switches with-contenv into a nop. I placed ''ENV S6_KEEP_ENV=1'' before first init and all the environment variable were visible. *[[https://vsupalov.com/docker-arg-env-variable-guide/|Docker ARG, ENV and .env - a Complete Guide]] *[[https://www.baeldung.com/ops/dockerfile-env-variable|How to Pass Environment Variable Value into Dockerfile]] *[[https://phoenixnap.com/kb/linux-export-command|Linux export Command with Examples]] *s6 *[[https://skarnet.org/software/s6-portable-utils/s6-env.html|The s6-env program ]] s6-env prints the current environment or modifies the environment before running a program. *[[http://skarnet.org/software/s6/s6-setuidgid.html|The s6-setuidgid program]] s6-setuidgid executes a program as another user. I used this to change the deluged and delugeweb programs not to run as root. *[[http://skarnet.org/software/s6/s6-envuidgid.html|The s6-envuidgid program]] s6-envuidgid potentially sets the UID, GID and GIDLIST environment variables according to the options and arguments it is given; then it executes into another program. =====Alpine Docker BusyBox s6-rc===== The Alpine docker image is build using musl, BusyBox and OpenRC, however I have setup to use s6-rc instead of OpenRC. The "standard" shell commands are build in the ash library with additional commands in Busybox, Busybox is a single file. Some addtional functionality can be found by using ''apk add util-linux''. See [[https://en.wikipedia.org/wiki/Util-linux|Wikipedia util-linux]] for a list of additional functionality in util-linux. A list of [[https://boxmatrix.info/wiki/BusyBox-Commands|BusyBox Commands]] =====References===== *[[https://deluge.readthedocs.io/en/latest/index.html|Deluge documentation]], unfortunately no specific instructions for Alpine Linux.... *[[https://privatevpn.com/support/getting-started/linux/linux/openvpn-cli|Support Documents OpenVPN CLI]], again not for Alpine Linux.... Other miscellaneous related references: *Alpine *[[https://docs.alpinelinux.org/user-handbook/0.1a/Working/apk.html|Working with the Alpine Package Keeper (apk)]] *[[https://wiki.alpinelinux.org/wiki/Writing_Init_Scripts|Writing Init Scripts]] *[[https://wiki.alpinelinux.org/wiki/OpenRC|OpenRC]] I am not using openRC *[[https://schoolofsoftware.com/Docker/alpine|How to Run "alpine" In Docker - Tutorial Exact Steps and Docker Tips & Ticks]] *[[https://dzone.com/articles/how-to-create-a-software-development-environment-o|DZone - How to Create a Development Environment on Alpine Linux]] *S6 *[[https://github.com/just-containers/s6-overlay| just-containers/s6-overlay]] *[[https://skarnet.org/software/s6-rc/s6-rc-compile.html|The s6-rc-compile program]] Describes the functionality of the S6-rc system *[[https://github.com/linuxserver/docker-deluge/blob/master/Dockerfile| linuxserver /docker-deluge]] *[[https://www.techtarget.com/searchitoperations/tutorial/Use-Docker-and-Alpine-Linux-to-build-lightweight-containers|Use Docker and Alpine Linux to build lightweight containers]] *[[https://www.docker.com/blog/how-to-use-the-alpine-docker-official-image/|How to Use the Alpine Docker Official Image]] *[[https://www.cyberciti.biz/faq/how-to-enable-and-start-services-on-alpine-linux/|How to enable and start services on Alpine Linux]] *[[https://docs.docker.com/engine/reference/run/|Docker Docs CLI reference]] <- docker_notes:docker-calibre|Back ^ docker_notes:index|Start page ^ docker_notes:docker-mailserver|Next ->