[TUTORIAL] Proxmox LXC container Alpine Linux - set up WireGuard VPN server - HOWTO - 05/2022 Rev1

konki

New Member
May 15, 2022
2
2
3
Restored thread due to banning by mistake
Rev1 new: Protection against UDP port scanning
ToDo: find an alternative to netifrc (not yet available for the apline linux stable branch) for loading the configuration file and and mount the wg0 network interface when booting the virtual machine.
Feel free to help: https://www.reddit.com/r/AlpineLinu...ting_wireguard_tunnel_at_boot_wg_setconf_way/

Hi,

I started using virtualization a short time ago, my objective was to replace several servers that were using development boards, that are now rare in France.
Proxmox VE was my choice as virtualization environment on a small mini-pc used as a personal server (Minis Forum UM250 AMD Ryzen V1605B 16Go - low power consumption).

Proxmox is easy to use for virtualization via LXC containers, the Wireguard VPN is powerful, now reliable and safe from a security point of view, Alpine Linux is powerful and light linux distribution.

I did not find any simple tutorial for the implementation of this project. I like to share and promote opensource software, so I offer you this explanation in the form of a small howto.

Computer science is not my job, so there may be some mistakes.

I/ Configure your Network Router/Firewall

<port forwarding>
51230 UDP 192.168.1.12 51230 wireguard server private IP and port
<Firewall policies>
WAN_LOCAL
51230 UDP accept

II/ Install Alpine Linux as LXC container (Proxmox VE 7.1-7)

Firewall must be enabled at the data center, the "ICMP_Port_Unreach_Error" server response to UDP port scanning is filtered by the default firewall configuration (Type3:Code3): Datacenter > Firewall > Options > Firewall > Edit > Yes > Ok

This will prevent the attacker from receiving packets indicating that a port is closed, thus skewing the results of his scan which will show all ports as either open or filtered.

Add CT Template to your local Proxmox VE Datacenter Node
local (YourNode) > CT Template > Templates > Download (search: alp )
alpine-3.15-default

Add a LXC to your Proxmox VE Datacenter Node
Create LXC Container Advanced (checked)
<General>
Node: YourNode
CT ID: 100 (in this tutorial)
Hostname: wireguard
Password: myverystrongpassword!
SSH public key: (optional)
Unprivileged container: checked
Nesting: checked
<Template>
Storage: local
Template: alpine-3.15-default_20211202_amd64.tar.gz
<Disks>
Storage: local-lvm
Disk size (GiB): 8
Mount options: noatime
ACLs: Default
<CPU>
Cores: 1
CPU units: 1024
<Memory>
Memory (GiB): 512
Swap (GiB): 512
<Network> configuarion for home server on local network IPv4 only
Name: eth0
Bridge: vmbr0
Firewall: unchecked
IPv4 static
IPv4/CIDR: 192.168.1.12/24
Gateway (IPv4): 192.168.1.1
<DNS>
use host settings

Settings on the Proxmox Host (1)
On the Proxmox Host there are some settings to be made for using the tun Device.

Bash:
YourNode login: youradmin
youradmin@YourNode:~# cd /etc/pve/lxc
youradmin@YourNode:/etc/pve/lxc# vi 100.conf
lxc.cgroup.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net dev/net none bind,create=dir

Then adjust the access rights to the tun Device:

Bash:
youradmin@YourNode:/etc/pve/lxc# chown 100000:100000 /dev/net/tun
youradmin@YourNode:/etc/pve/lxc#

III/ installation of the required packages and set localtime

Open a terminal on your Alpine VM

wireguard login: root
Password: myverystrongpassword!

Alpine Linux package updates and install all required packages (2)
Bash:
wireguard:~# apk update
wireguard:~# apk upgrade
wireguard:~# apk add tzdata
wireguard:/usr/share/zoneinfo/Europe# cp Paris /etc/localtime
wireguard:/usr/share/zoneinfo/Europe# date

wireguard:~# apk add -U wireguard-tools
wireguard:~# apk add wireguard-tools-wg

wireguard:~# apk add bash

wireguard:~# apk add curl
wireguard:~# apk -U add libqrencode

wireguard:~# apk add iptables && rc-update add iptables


Now that all the tools are installed, you can setup the interface wg0.
We choose the port 51230 and the private ip 192.168.1.12 for wireguard server.

Bash:
wireguard:~# vi /etc/network/interfaces
auto lo
iface lo inet loopback
iface lo inet6 loopback

auto eth0
iface eth0 inet static
        address 192.168.1.12/24
        gateway 192.168.1.1
        hostname $(hostname)
      
auto wg0           
iface wg0 inet static
       requires eth0
       use wireguard
       address 10.123.0.1
       post-up iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;iptables -A FORWARD -o wg0 -j ACCEPT
       post-down iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;iptables -D FORWARD -o wg0 -j ACCEPT

Allow forward :

Bash:
wireguard:~# cd /etc
wireguard:/etc# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
wireguard:/etc# echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
wireguard:/etc# echo "net.ipv4.conf.all.proxy_arp = 1" >> /etc/sysctl.conf
wireguard:/etc/conf.d# rc-update add sysctl

Edit iptable config and enable forwarding: change IPFORWARD= "no" to "yes"
Bash:
wireguard:/etc/conf.d# vi iptables
# Enable/disable IPv4 forwarding with the rules
IPFORWARD="yes"

Restart iptable:
Bash:
wireguard:/etc/conf.d# /etc/init.d/iptables save
wireguard:/etc/conf.d# rc-service iptables restart
wireguard:/etc/conf.d# /etc/init.d/ip6tables save
wireguard:/etc/conf.d# rc-service ip6tables restart

Then we add wireguard in module then we restart the network :

Bash:
wireguard:~# echo wireguard >> /etc/modules
wireguard:~# /etc/init.d/networking restart

From here we have a wg0 interface which is visible (status down but it is normal), we go on with the configuration.

III/ Wireguard Server configuration

Bringing up an interface using ifupdown-ng (3) (4) (5)
We'll use the plain wg command and ifupdown-ng.
The given configuration file will be loaded using *wg setconf* and not with *wg-quick*. *No Address line in the [Interface] section. Otherwise, the interface will not come up*

We now generate a private key (privatekey) and a public key (publickey) that our server will use:

Bash:
wireguard:~# cd /etc/wireguard
wireguard:~# umask 077
wireguard:~# ls
wireguard:~# wg genkey | tee privatekey | wg pubkey > publickey
wireguard:/etc/wireguard# cat publickey
serverpublickeyserverpublickeyserverpublicke
wireguard:/etc/wireguard# cat privatekey
serverprivatekeyserverprivatekeyserverprivat

The server's private key should never be shared. The public key is what we will give to the clients so they can connect to our server.

Then we prepare the configuration file /etc/wireguard/myconfig.conf linked to the wg0 interface:

Bash:
wireguard:~# vi myconfig.conf
wireguard:/etc/wireguard# echo "[interface]" >> /etc/wireguard/myconfig.conf
wireguard:/etc/wireguard# echo "ListenPort = 51230" >> /etc/wireguard/myconfig.conf
wireguard:/etc/wireguard# echo "PrivateKey = $(cat privatekey)" >> /etc/wireguard/myconfig.conf
wireguard:/etc/wireguard# vi myconfig.conf

[interface]
ListenPort = 51230
PrivateKey = serverprivatekeyserverprivatekeyserverprivat

Sets the current configuration of interface wg0 to the contents of the configuration file:
Bash:
wireguard:/etc/wireguard# ifdown wg0
wireguard:/etc/wireguard# /etc/init.d/networking restart
wireguard:/etc/wireguard# wg setconf wg0 myconfig.conf
wireguard:/etc/wireguard# ifup wg0
wireguard:/etc/wireguard# wg interface: wg0
  public key: serverpublickeyserverpublickeyserverpublicke
  private key: (hidden)
  listening port: 51230

Verification
Verify that WireGuard is up and running using the ss command/netstat command/lsmod command along with the grep command:
Bash:
wireguard:~# netstat -tulpn | grep 51230
udp        0      0 0.0.0.0:51230           0.0.0.0:*                           -
udp        0      0 :::51230                :::*                                -

Check or find your public IP address from command line on a Linux:
Bash:
wireguard:~# curl checkip.amazonaws.com

Check forwarding:
Bash:
wireguard:~# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

Scan the server wireguard port UDP 51230, disable the firewall at Datacenter level if you want to do this test, otherwise all ports appear as open!
from a linux terminal

Bash:
~ sudo nmap -sU 192.168.1.12 -p 51230
[CODE=bash]
~ sudo nmap -sU subdomain.domain.com -p 51230


IV/ Add client to the server (4)

Create a client configuration file with Pre-Shared Key (PSK)
The PSK is optional, but adds significant security. Both the client and the server need a copy of this final PSK element.

Bash:
wireguard:~# cd /etc/wireguard
wireguard:/etc/wireguard# umask 077
wireguard:/etc/wireguard# mkdir client
wireguard:/etc/wireguard# cd client
wireguard:/etc/wireguard/client# mkdir peer1-computer1
wireguard:/etc/wireguard/client# cd peer1-computer1
wireguard:/etc/wireguard/client/peer1-computer1# wg genkey | tee privatekey | wg pubkey > publickey
wireguard:/etc/wireguard/client/peer1-computer1# wg genpsk > peer1psk
wireguard:/etc/wireguard/client/peer1-computer1# cat privatekey
peer1privatekeypeer1privatekeypeer1privateke
wireguard:/etc/wireguard/client/peer1-computer1# cat publickey
peer1publickeypeer1publickeypeer1publickeype
wireguard:/etc/wireguard/client/peer1-computer1# cat peer1psk
peer1pskpeer1pskpeer1pskpeer1pskpeer1pskpeer

IP address is incremented above our Wireguard server's IP (10.123.0.1 in this tutorial) and used /32 which only allocates a single address
10.123.02 for peer1
Endpoint is the server Public IP address (exposed to the internet) or a domain name pointing to your server and wireguard service port
Wildcard 0.0.0.0/0: automatically encrypts any packet and sends it through the VPN tunnel.

Bash:
wireguard:/etc/wireguard/client/peer1-computer1# echo "[interface]" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "Address = 10.123.0.2/32" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "DNS = 192.168.1.1, 8.8.8.8" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "PrivateKey = $(cat privatekey)" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "[Peer]" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "Endpoint = subdomain.domain.com:51230" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "AllowedIPs = 0.0.0.0/0, ::0/0" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "PublicKey = $(cat /etc/wireguard/publickey" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# echo "PresharedKey = $(cat peer1psk)" >> peer1-computer1.conf
wireguard:/etc/wireguard/client/peer1-computer1# vi peer1-computer1.conf
[interface]
Address = 10.123.0.2/32
PrivateKey = peer1privatekeypeer1privatekeypeer1privateke
DNS = 192.168.1.1, 8.8.8.8
[Peer]
Endpoint = subdomain.domain.com:51230
AllowedIPs = 0.0.0.0/0, ::/0
PublicKey = serverpublickeyserverpublickeyserverpublicke
PresharedKey = peer1pskpeer1pskpeer1pskpeer1pskpeer1pskpeer

and so on...

Add client to the server config
Bash:
wireguard:/etc/wireguard# vi myconfig.conf
[interface]
PrivateKey = serverprivatekeyserverprivatekeyserverprivat
ListenPort = 51230

[Peer]
PublicKey = peer1publickeypeer1publickeypeer1publickeype
AllowedIPs = 10.123.0.2/32
PresharedKey = peer1pskpeer1pskpeer1pskpeer1pskpeer1pskpeer

[Peer]
PublicKey =
AllowedIPs = 10.123.0.3/32
PresharedKey =

[Peer]                                                                                                                            
PublicKey =
AllowedIPs = 10.123.0.4/32                                                    
PresharedKey =

and so on...

load the configuration of the wg0 interface:

Bash:
wireguard:/etc/wireguard# ifdown wg0
wireguard:/etc/wireguard# /etc/init.d/networking restart
wireguard:/etc/wireguard# wg setconf wg0 myconfig.conf
wireguard:/etc/wireguard# ifup wg0
wireguard:/etc/wireguard# wg

V/ Configure your clients

All that remains is to import the configuration file on the client.
install wireguard client ( https://www.wireguard.com/install/ ),
If your client is under Windows, export client config with Notepad++ (copy/paste) and use: Edit > EOL conversion > Unix(LF) before saving the configuration file.
If ever an import option by qrcode is possible (Android or iOS client), the solution is simple:
Bash:
qrencode -t ansiutf8 < /etc/wireguard/client/peer-smartphone/peer-smartphone.conf

Speedtest through vpn tunnel:

Bash:
wireguard:~# apk install iperf3
wireguard:~# iperf3 -s

ctrl-c to exit

Client:
iperf3 -c remotehost -i 1 -t 30 #Run a 30 second tests, giving results every 1 second
iperf3 -c remotehost -i 1 -t 30 -R #Run a test from remotehost to localhost

Server Minis Forum UM250 : Max CPU usage 0.003 Max Memory usage 6.68 MiB Wireguard Proxmox VE LXC Alpine Linux 3.15
Enjoy!

konki

Bibliography:
https://kayomo.de/blog/wireguard-unter-proxmox-installieren/ (1)
https://www.tecmint.com/apk-command-examples/(2)
https://wiki.alpinelinux.org/wiki/Configure_a_Wireguard_interface_(wg) (3)
https://github.com/ifupdown-ng/ifupdown-ng/blob/main/doc/interfaces-wireguard.scd (4)
https://www.smarthomebeginner.com/linux-wireguard-vpn-server-setup/ (4)
https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 (5)
https://pve.proxmox.com/pve-docs/pve-admin-guide.html (6)
 
If I set AllowedIPs = <LAN subnet> in the wireguard conf, I can access my local area network, however for some reason the bandwidth is somehow throttled if the VM (wireguard peer) is inside proxmox VE.

I tried the same setup but instead I used virtual box, the bandwidth is OK.

I tested using scp copying a file from within my local area network (source machine is not on wireguard, only routed through a wireguard peer). What do you think is the cause of the bandwidth throttling within proxmox VE?
 
I don't have any clear opinion, does the wireguard server run in a VM or in a container?

For a VM try to change the network adapter to the VirtIO (paravirtualized) option. This driver takes into account the virtualized execution
and just passes the network traffic between the VM and the host in the most straightforward way possible.
The settings of the scci controller and the disk can also have an influence, try Virtio scsi single and for the virtual disk the options discard and ssd emulation

A LXC container for a single light server application seems more appropriate than a VM, it is very efficient with a container running alpine linux and I don't encounter any malfunctioning despite the sharing of the host kernel (proxmox 7.1 debian kernel 5.10.)
To be precise, these are virtual environments rather than virtual machines, since we do not emulate the physical layer of the machine (as VirtualBox would do, for example). LXC only allows you to create Linux machines, but the impact on performance is negligible.
 
Last edited:
All that configuration is ridiculous but thank you very much for this, it must have taken forever. Thanks again
 
i'm stuck can someone help??
i can not get wg0 up


Wireguard:/etc/wireguard# ifdown wg0
Wireguard:/etc/wireguard# /etc/init.d/networking restart
* WARNING: you are stopping a boot service
* Stopping networking ... * lo ... [ ok ]
* eth0 ... [ ok ]
* Starting networking ... * lo ... [ ok ]
* wg0 ...RTNETLINK answers: File exists
ifup: failed to change interface wg0 state to 'up'
[ !! ]
* eth0 ... [ ok ]
Wireguard:/etc/wireguard# ifup wg0
RTNETLINK answers: File exists
ifup: failed to change interface wg0 state to 'up'
Wireguard:/etc/wireguard# wg interface: wg0
Invalid subcommand: `interface:'
Usage: wg <cmd> [<args>]

Available subcommands:
show: Shows the current configuration and device information
showconf: Shows the current configuration of a given WireGuard interface, for use with `setconf'
set: Change the current configuration, add peers, remove peers, or change peers
setconf: Applies a configuration file to a WireGuard interface
addconf: Appends a configuration file to a WireGuard interface
syncconf: Synchronizes a configuration file to a WireGuard interface
genkey: Generates a new private key and writes it to stdout
genpsk: Generates a new preshared key and writes it to stdout
pubkey: Reads a private key from stdin and writes a public key to stdout
You may pass `--help' to any of these subcommands to view usage.
 
i'm stuck can someone help??
i can not get wg0 up


Wireguard:/etc/wireguard# ifdown wg0
Wireguard:/etc/wireguard# /etc/init.d/networking restart
* WARNING: you are stopping a boot service
* Stopping networking ... * lo ... [ ok ]
* eth0 ... [ ok ]
* Starting networking ... * lo ... [ ok ]
* wg0 ...RTNETLINK answers: File exists
ifup: failed to change interface wg0 state to 'up'
[ !! ]
* eth0 ... [ ok ]
Wireguard:/etc/wireguard# ifup wg0
RTNETLINK answers: File exists
ifup: failed to change interface wg0 state to 'up'
Wireguard:/etc/wireguard# wg interface: wg0
Invalid subcommand: `interface:'
Usage: wg <cmd> [<args>]

Available subcommands:
show: Shows the current configuration and device information
showconf: Shows the current configuration of a given WireGuard interface, for use with `setconf'
set: Change the current configuration, add peers, remove peers, or change peers
setconf: Applies a configuration file to a WireGuard interface
addconf: Appends a configuration file to a WireGuard interface
syncconf: Synchronizes a configuration file to a WireGuard interface
genkey: Generates a new private key and writes it to stdout
genpsk: Generates a new preshared key and writes it to stdout
pubkey: Reads a private key from stdin and writes a public key to stdout
You may pass `--help' to any of these subcommands to view usage.
same problem cannot ifuo wg0 interface
 
Was there an solution found, I am stuck with the same issue :-(

Code:
/etc/init.d/networking restart
 * WARNING: you are stopping a boot service
 * Stopping networking ... *   lo ... [ ok ]
 *   eth0 ... [ ok ]
 * Starting networking ... *   lo ... [ ok ]
 *   wg0 ...RTNETLINK answers: File exists
ifup: failed to change interface wg0 state to 'up'
 [ !! ]
 *   eth0 ... [ ok ]

The "wg interface: wg0" part looks like an type error, I susspect following command is meant :

wg show wg0
 
Got it to work with the wg-quick method ( e.g. as described here : https://www.stavros.io/posts/how-to-configure-wireguard/ )
To autostart I created an alpine start script as described e.g. here https://techoverflow.net/2022/11/26/how-to-autostart-wireguard-wg-quick-on-boot-on-alpine-linux/

Take care that you then NOT add the interface parameters to the file /etc/network/interfaces
Also I named the config wg0.conf in /etc/wireguard and in the start script.

This works for me without the error : "wg0 ...RTNETLINK answers: File exists"
 

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!