I will explain you how to run Wireguard on your Qnap NAS as a docker container using Container Station.
Introduction
I have been using Wireguard for some time on Linux systems with Android and Linux clients. I am very happy with its performance an reliability. Wireguard is a fast and modern point-to-point vpn protocol, easy to setup and very performant. It uses strong and modern cryptography and has a small code footprint. You can find out more on the Wireguard site.
Today I will show you how to run Wireguard on your Qnap NAS server as a docker container, using Qnap Container Station. This way you will be able to externally connect to your NAS in a very secure way. Also If you want you will be able to reach other systems in your home network through the vpn tunnel.
Note that we wont’t be using the kernel implementation of Wireguard. Wireguard is included since the 5.6 version on the Linux kernel. At this moment my NAS is using version 4.14 version of the kernel, so I cannot use the Wireguard kernel module. I do not know if Qnap plans to include the module or update the kernel to a valid version in a near future but I figure out it can take a while.
Instead we will be using the userspace implementation of Wireguard, written in Go. This implementation is not as performant as the kernel implementation, even though I have been also testing it with very good results.
Docker container
We will need Container Station installed on our Qnap. Also we need to create a persistent folder (e.g. /share/Container/wireguard) to keep Wireguard configuration files and not lose them in case that we need to recreate the container.
To create the container open Container Station, then click on Create, and on the top right click on Create Application button. This will open a dialog where you can paste a Docker Compose file. Set an application name and paste the YAML code below.
version: '3.3' services: wireguard: image: masipcat/wireguard-go:latest container_name: wireguard cap_add: - NET_ADMIN sysctls: - net.ipv4.ip_forward=1 volumes: - /dev/net/tun:/dev/net/tun # Persistent folder you created before - /share/Container/wireguard:/etc/wireguard environment: - WG_COLOR_MODE=always - LOG_LEVEL=debug ports: - 51820:51820/udp privileged: true restart: unless-stopped
Create keys for server and client
Next we need to create some keys for the peers acting as server and client and also a configuration file for each peer. We will call ‘server’ to our Qnap NAS peer and ‘client’ to the device that will connect to the NAS (e.g. phone, laptop).
We need to execute some commands in our container to generate public and private keys for the client and server. This can be done directly from the container terminal. You can access the container terminal from Container Station overview page, unfolding the application you created, and clicking in the terminal button (>_). Type ‘/bin/bash’ as your command, and then ‘OK’. A new tab will open on your browser with a terminal from our container.
To generate the server keys execute following commands:
bash-5.0# echo -n "server private key: ";wg genkey server private key: GPZ/qF/GFCMi65neErSj1KxslsmFOmKQdaB/8GRuLWU= bash-5.0# echo -n "server public key: ";echo GPZ/qF/GFCMi65neErSj1KxslsmFOmKQdaB/8GRuLWU=|wg pubkey server public key: 2NPyahRD4k0rjg1ERAA1873E/s42JSmoPz+vpVgbzW4=
Client keys are generated in the same way:
bash-5.0# echo -n "client private key: ";wg genkey client private key: wKzA7588TIQ5r9IOimBZdJoFdYniEfRWojaX412BrHo= bash-5.0# echo -n "client public key: ";echo wKzA7588TIQ5r9IOimBZdJoFdYniEfRWojaX412BrHo=|wg pubkey client public key: LInzz/1nT/x+vbuQLWbk85rQw2Ca63huFuhWMPDqHT8=
Keys will be shown on screen, you will need them in next step to create the server and client configuration files. Note that the public key is derived from the corresponding private one.
Server configuration file
Enter the directory /etc/wireguard. Then create the file wg0.conf.
cd /etc/wireguard sh -c 'umask 077; touch wg0.conf'
You can edit the file from terminal with vi editor or, if you have Text Editor installed on your NAS you can access it from the mapped folder (e.g. /share/Container/wireguard/wg0.conf)
## server configuration (wg0.conf) [Interface] Address = 10.13.13.1/24 ListenPort = 51820 PrivateKey = <server privatekey> ## uncomment next two lines if you also want to gain access to your entire lan or if you ## want all traffic to go through the tunnel #PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE #PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] PublicKey = <client publickey> AllowedIPs = 10.13.13.2/32
- Replace ‘server privatekey’ and ‘client publickey’ by the ones created before.
- Address: You can choose any address that does not overlap with your private LAN, for the examples I am using IPs from the 10.13.13.0/24 network. Modify server and client configuration files if you change it.
- ListenPort: you can use whatever port you want. Just make sure to forward it in your router to your NAS server and configure it in the docker-compose yaml and in the client configuration.
- If you want to reach your entire network from the client or send all traffic through the tunnel, uncomment both PostUp and PostDown lines.
It is time to restart the container to apply the configuration and to bring the interface wg0 up. You can restart the container from the overview page on Container Station. After this, your Wireguard server is ready to accept connections.
Client configuration file
Create the client configuration file client1.conf.
cd /etc/wireguard sh -c 'umask 077; touch client1.conf'
## client configurtion (client1.conf) [Interface] Address = 10.13.13.2/24 PrivateKey = <client privatekey> DNS = 1.1.1.1 # use custom dns, optional [Peer] PublicKey = <server publickey> Endpoint = <your public ip>:51820 AllowedIPs = 10.13.13.0/24 ## if you want also reach you remote lan, add it to AllowedIPs ## e.g. AllowedIPs = 10.13.13.0/24, 192.168.1.0/24 ## if you want all traffic go over the tunnel, add 0.0.0.0/0 ## e.g. AllowedIPs = 0.0.0.0/0 ## uncomment below to keep the connection alive #PersistentKeepalive = 25
- This client config should be copied to the client device you want to use (e.g. mobile, laptop) in a secure way.
- AllowedIPs: a comma separated list of networks that should be reached from the client. Add 0.0.0.0/0 if you want all client traffic go through the tunnel.
- PersistentKeepalive: uncomment this line if you want to keep the tunnel up even with no traffic, or if you are experiencing issues because of being behind nat.
Once you copy this configuration to your client and enable it, you should be able to reach your server tunnel ip, and if configured to do so, to your NAS and your internal network, or pass all the traffic through the tunnel.
Conclusion
We have seen how to configure Wireguard on our Qnap server as a docker container. If you have any question or comment, please let me know.
Hi,
I just used your method to setup wireguard on my T451+(intel QNAP), but it was failed. The concole message is as below,
Unable to access interface: Protocol not supported
[#] ip link delete dev wg0
Cannot find device “wg0”
[#] ip link add wg0 type wireguard
RTNETLINK answers: Not supported
Would you please advice me how could I start the service ?
Thank you.
Hi, It sounds strange to me, as your ts-451 and my ts-453 are quite similar. I really do not know what the issue could be.
I have never saw these lines on my container console.
These two ones are somehow normal, as it tries to load the kernel module and this is not possible, that is why we are using the userspace implementation of wireguard. Right after this lines my container console show how the container uses this implementation.
Are those lines the only ones that appear in your console? If there are more messages, provide me all the console output to check if I can see anything else.
You can also check a few things:
– From inside the container terminal, check If ‘/etc/wireguard/wg0.conf’ is properly configured (paste it here for checking).
– From inside the container terminal, execute ‘ip address’ command and check if wg0 interface is shown there.
– Check if ‘/dev/net/tun’ exists in your nas, not inside the container, you will need to ssh into your nas to check this with ‘ls -l /dev/net/tun’
I am sorry I cannot say much more, If you can pass me your configurations (wg0.conf, compose file, …) and as much logs as you can, I will be glad in review them to see if I can find something than can cause the issue.
Please let me know of any advance.
Regards.
thank u it’s worked
Hi, I’m glad it worked, best regards.
It worked on QNAP TS-251+.
Thank you!
Glad it worked. thanks for your comment.
This is not working on my TS-451+. I used the instructions as directed. However, nothing is connecting. Using a port scanner to my public IP shows that 51820 is closed. I have it forwarding to my NAS with an internal IP of 192.168.0.10. The docker has an IP of 172.29.4.2. How this was generated is beyond my knowledge of the QNAP virtual switch. I tried to port forward to that as well on my router, but I get the same results – port closed, incoming traffic denied.
The VPN Client on my phone sends data but never gets anything back. I’ve verified the generated keys, but if the data is never even reaching the server, then nothing will work anyway. I have QuFirewall turned off as well. Any ideas?
Hi, This is strange. Provided You have forwarded 51820 UDP port on your router to your NAS internal ip, packets should be arriving to it. Container exposes this port (51820/UDP) so you should be able to check it with a command like netstat on your nas command line (try ‘netstat -puntl|grep 51820’). If all of this is fine, perhaps there is something on the container logs to guide us to the cause of this issue.
By the way, last versions of qnap firmware ships with more modern kernels that already supports wireguard natively, so the qnap vpn app should support it as well. Perhaps you can try this way as It is more effective an reliable. Hope this helps.
I’m experiencing a similar situation with my QNAP 253A. Although the required port for the connection is available, I’m unable to establish a connection to the container. It’s worth noting that the QuFirewall is not installed on my device. Here’s the log obtained by using SSH to access the NAS.
[~] # netstat -puntl|grep 51820
udp 0 0 0.0.0.0:51820 0.0.0.0:* 26793/dockerd
[~] # telnet localhost 51820
telnet: can’t connect to remote host (127.0.0.1): Connection refused
[~] # telnet 127.0.0.1 51820
telnet: can’t connect to remote host (127.0.0.1): Connection refused
Hi Joe, as stated in your netstat output, port 51820 is open so I will assume that the container is exposing that port properly.
The problem with your tests (telnet) is that you are trying to establish a TCP connection against an UDP port and that would never is going to work. I would suggest you to do a real test, like configuring a wireguard client and trying to connect from it. Please, let me know If it this test finally worked.
As a side note, I will comment that some time ago qnap added native wireguard support to QTS firmware, so perhaps there is no need to use the userspace implementation nowadays. I do not know you use case, just letting you know.
Hope this helps.
For whatever reason that YAML won’t validate for me, and I confirmed it’s due to the line: – /share/Container/wireguard:/etc/wireguard
if I comment out that line, it works. How do I create the folder prior to this step? I actually did create a “wireguard” folder inside “Container” folder on my DataVol1. But what if I had multiple data volumes, how would container station know where to look?
Ignore my previous comment. The issue was that the QNAP interface didn’t like the hashtag (#) comment. I deleted that line and it worked. 🙂
Hello Michael, I’m glad it finally worked for you. As I told Joe, you can also try the native WireGuard version if it is supported by your QNAP firmware. Best regards.