VPS: SOCKS5 and Wireguard (20241012)

This post details using our VPS as a SOCKS5 Proxy for a single web browser and how to set up wg_easy to create a peer-to-peer network for accessing self-hosted services.

Oct 12, 2024
🧬
This post details using our VPS as a SOCKS5 Proxy for a single web browser and how to set up wg_easy to create a peer-to-peer network for accessing self-hosted services.
 
Revision: 20241012-0 (init: 20241012)
 
docker compose setup for wg_easy, including peer configuration. Also discussed is SOCKS5 Proxying for a single browser and Tailscale.
 
 
For this setup, we rely on an existing Virtual Private Server or a remote host to connect to using ssh with docker compose or a tool to deploy compose stacks. We will also use cloudflared and ufw-docker. We have discussed those in previous blog posts and will ask you to check those content for additional details:

Preamble

SOCKS5

Socket Secure version 5 (SOCKS5) is a versatile networking protocol that serves as an intermediary between a client and a server, acting as a general framework proxy capable of handling various types of internet protocols. The primary purpose of SOCKS5 is to enable clients to access servers and services that may be separated by firewalls or other network barriers while providing enhanced security and performance compared to its predecessors.
It is helpful to facilitate secure access to internal resources from external networks. The protocol's ability to work with various internet traffic while maintaining security features makes it a popular choice for VPN services, anonymous browsing, and other applications requiring secure and flexible network routing.
SOCKS5 doesn't encrypt traffic; as such, we will use it with SSH to provide an encrypted connection to our remote VPS.

Wireguard

WireGuard is a modern, high-performance Virtual Private Network (VPN) technology that offers several advantages over traditional VPN protocols. It is an open-source VPN protocol that is fast, simple, and secure. WireGuard utilizes state-of-the-art cryptography to ensure robust protection. It runs inside the Linux kernel, improving performance and reducing overhead. It uses UDP for communication, contributing to its speed. It supports an optional layer of symmetric-key cryptography for enhanced security, including potential post-quantum resistance (with optional pre-shared symmetric keys).
WireGuard exclusively uses UDP for its network communication, which avoids TCP-over-TCP issues (using UDP avoids the performance problems associated with tunneling TCP traffic over another TCP connection) and provides a connection-less protocol.
Wireguard allows peers to connect using PrivateKey, PublicKey, and optional PresharedKey.
 
A server /etc/wireguard/wg0.conf configuration file usually contains an Interface section and one or many Peer:
[Interface] PrivateKey = <server-private-key> Address = 10.8.0.1/24 ListenPort = 51820 PostUp = <iptables rules> PostDown = <iptables rules> [Peer] PublicKey = <peer1-public-key> PreSharedKey = <peer1-server-pre-shared-key> AllowedIPs = 10.8.0.2/32
(and in some cases some PostUp and PostDown configurations for iptables setup)
 
A client (here “peer1”) configuration will usually contain:
[Interface] PrivateKey = <peer1-private-key> Address = 10.8.0.2/32 [Peer] PublicKey = <server-public-key> PreSharedKey = <peer1-server-pre-shared-key> AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = <vps_ip>:<wireguard_port>
The server’s public key, which can be freely shared, is used by peer1 to encrypt messages. The private key, kept secret by the server, is used to decrypt those encrypted messages. This system allows for secure message exchange over insecure channels, as only the intended recipient with the correct private key can decrypt messages encrypted with their public key.
In this example, “Peer1” and the server have also defined the optional pre-shared key. Peer1 will obtain a private IP on the Wireguard VPN of 10.8.0.2 (the Address portion) and ALL of the peer’s traffic is set to go over the created tunnel (AllowedIPs routes all IPv4 and IPv6 traffic to use the tunnel).

Tailscale

👉
Disclaimer: I have been using Tailscale extensively since 2021, and use it in addition to this VPS setup.
Although we will not use Tailscale in this post, it is an extremely powerful solution to create a Mesh network of peers connected with one another and we encourage endusers to investigate it. It provides similar capabilities (and more) to our proposed wg_easy setup, but depending on the relay used, the VPS hosted Wireguard often provide a faster communication.
Tailscale has gained popularity among self-hosters due to its unique approach to networking and several key features that make it particularly suitable for personal and small-scale deployments.
Tailscale is a VPN service that creates secure, encrypted point-to-point connections between devices using the WireGuard protocol, providing a mesh network which allows device our private network (our tailnet) to communicate securely with each other, regardless of their physical location. Tailscale employs advanced NAT traversal techniques to establish direct connections between devices, even when they're behind firewalls or complex network configurations.
Tailscale is simple to install and configure, works on many different types of devices.
Unlike traditional VPNs (like our VPS wg_easy setup), Tailscale doesn't require setting up and maintaining a central VPN server, reducing complexity and potential points of failure.
And for Unraid users, Tailscale will soon be even more integrated with the solution, as described in https://unraid.net/tailscale

SOCKS5 via SSH: browser access

Prerequisites:
  • In this setup we will use vps as our configured ssh-ready host, supporting ssh key login.
Setup the SOCKS5 compatible proxy; in the Foxy Proxy menu, create a new entry of type SOCK5 using 127.0.0.1 and 3128 for the Hostname and Port. Name it as you prefer; we will use a generic entry to remind us of the base ssh command to use. It is also possible to enable the Proxy DNS option to send DNS requests to the VPS’ DNS instead of resolving those locally.
notion image
The Proxy will not function unless it is activated in the FoxyProxy menu:
notion image
Once the proxy configuration is prepared, connect to the remote host and enable the SOCKS5 proxy
ssh -N -D 3128 vps
Where the -N tells SSH not to execute a command and the -D <port> opens the SOCK5 tunnel on the specified port. The port for the ssh tunnel and the configured SOCKS5 proxy need to match.
Remember to disable the tunnel in FoxyProxy and ctrl+c-ing the ssh when done.
Using this method the entire HTTP(S) communication from your web browser will be tunneled through the SOCK5 proxy (including the DNS resolving through the Proxy DNS)

wg-easy: peer-to-peer access

Pre-requisite:
  • vps as our configured ssh-ready host, supporting ssh key login.
  • a CNAME set at the domain’s DNS to provide an easy name for our vps (ie go from vps12345-patlabor.myfavoritevps.datacenter.tld to vps.example.com
  • ufw and ufw-docker enabled on the host as described in “Ubuntu 24.04 VPS Hardening”; we will block access to the WebUI but authorize access to the Wireguard port.
 
wg-easy (more details at https://github.com/wg-easy/wg-easy) is a very convenient and easy way to define a Wireguard VPN and create peers.
 
Our proposed compose.yaml for the service is as follows (direct download link):
services: wg-easy: environment: - LANG=en - WG_HOST=vps.example.com # Adapt with the CNAME set at your DNS - PASSWORD_HASH=${PASSWORD_HASH} # set the secret - WG_DEVICE=ens3 # adapt with the network interface of the NIC that will respond to the wireguard service - PORT=51821 # WebUI access (TCP) to be accessed with Cloudflare ZeroTrust - WG_PORT=51820 # Wireguard port (UDP) to be opened through ufw-docker - WG_DEFAULT_ADDRESS=10.10.10.x # Authorized subnet - WG_DEFAULT_DNS=1.1.1.1 # use Cloudflare's DNS - WG_MTU=1420 - WG_ALLOWED_IPS=10.10.10.0/24 # default configuration is to only allow peers to communicate with one another - WG_PERSISTENT_KEEPALIVE=25 # Value in seconds to keep the "connection" open - UI_TRAFFIC_STATS=true # Enable detailed RX / TX client stats in Web UI - UI_CHART_TYPE=2 # Area chart - UI_ENABLE_SORT_CLIENTS=true # Enable UI sort clients by name image: ghcr.io/wg-easy/wg-easy container_name: wg-easy volumes: - ./etc_wireguard:/etc/wireguard ports: - 51820:51820/udp # if you changed WG_PORT, adapt here - 51821:51821/tcp # if you changed PORT, adapt here restart: unless-stopped cap_add: - NET_ADMIN # grants elevated network-related privileges to the container - SYS_MODULE # allows the container to load and unload kernel modules sysctls: - net.ipv4.ip_forward=1 # enables IP forwarding, ie to act as a router, forwarding IP packets from one network interface to another - net.ipv4.conf.all.src_valid_mark=1 # affects how the system handles packet routing and marking: it enables the kernel to consider the packet mark when making routing decisions labels: - com.centurylinklabs.watchtower.enable=true
Set a .env file containing your PASSWORD_HASH= value. See https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md for details on how to create this hash. We note that despite the fact that we intend to place the WebUI behind Cloudflare’s authorized emails only Zero Trust, setting a secure password is still recommended.
We are deploying the stack using Dockge; please see the https://blg.gkr.one/20240706-dockge/ post for additional details.
After starting the service, a wg0.conf will be placed in the etc_wireguard directory. That file is the Wireguard configuration in use defining the wg0 interface. The content of the file is automatically generated by the WebUI each time a new peer is added. In this file, we will find the automatically generated PrivateKey for the server as well as two iptables commands for the PostUp and PostDown defining POSTROUTING, MASQUERADEing and FORWARDing:
  • POSTROUTING is a chain in the NAT (Network Address Translation) table of iptables. It allows packets to be altered as they are leaving the firewall's external device.
  • MASQUERADEis a type of NAT action that translates host IPs in a private network into a single IP address.
  • FORWARD is a chain used for packets that are routed through the current host to allow traffic to pass between different network interfaces.
 
After the system is up, in our setup, becauseufw (and ufw-docker) are configured to block any request to the newly created, we need to do two types of additional configurations:
  1. Configure the Cloudflare Dashboard to setup an email protected zero trust layer to access the WebUI (i.e. we are not exposing the WebUI directly). Please see "VPS: Cloudflare Zero Trust access to Web Applications” for instructions on this process. Our url will be https://wgz.example.com
  1. Enable clients to connect to the UDP port of our newly created wg-easy docker container (do a docker ps to confirm the container’s name), using
sudo ufw-docker allow wg-easy 51820/udp
At this point, the WebUI is up and protected behind Cloudflare’s Zero Trust and the UDP port is open on the VPS and answering confirmed clients (both using cryptographic key exchange and pre-shared key).
The next step consists of adding peers to the WebUI.

Adding peers

After proceeding through the Zero Trust challenge at wgz.example.com we are prompted to enter the WebUI’s password. That secret was loaded as an environment variable from our compose.yaml.
notion image
When selecting the +New option we are prompted with a UI to enter the name of the peer. We will use test.
notion image
Our test peer gets the first IP available on the list of WG_DEFAULT_ADDRESS.
  • On the left side (top to bottom):
    • it is possible to modify the name of the peer.
    • it is also possible to change the assigned IP such that the host matches the last digits of the system in your LAN for example. If you check the PostUp entry in the etc_wireguard/wg0.cong you should see iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o ens3 -j MASQUERADE. This rule sets up IP masquerading for all traffic coming from the 10.10.10.0/24 network and going out through the ens3 interface; as such only modify this value to be within that range.
  • On the right side (left to right):
    • the toggle enables or disables the peer in the wg0.conf file
    • the QR code button will display a QR code that can be used to load the key on compatible clients.
    • the download button will download the test peer configuration file.
    • the delete button will remove test from the list of peers.
 
After downloading it, the test.conf file contains:
[Interface] PrivateKey = <peer1privatekey> Address = 10.10.10.2/24 DNS = 1.1.1.1 MTU = 1420 [Peer] PublicKey = <serverpublickey> PresharedKey = <peer1server-presharekey> AllowedIPs = 10.10.10.0/24 PersistentKeepalive = 25 Endpoint = vps.example.com:51820
In there we see:
  • the Interface section, defining the local peer (test), containing the PrivateKey of the peer, the assigned Address of this peer, the DNS and MTU as configured at compose.yaml time.
  • the Peer section, defining the remote peer (ie our VPS), with its PublicKey, the PreSharedKey, the list of AllowedIPs (ie what subnets would go through this tunnel; here only other peers on the 10.10.10.0/24 can be reached, while an AllowedIPs of 0.0.0.0/0, ::/0 would redirect all traffic through the VPN tunnel), how often the peer verified communication with the server (PersistentKeepAlive, in seconds) and the Endpoint where the server is answering (here vps.example.com on port 51820, as defined in the compose.yaml file).

Client configuration

Wireguard App: compatible clients

On Windows, MacOS, iOS and Android you can find compatible clients at https://www.wireguard.com/install/
They will work with either the configuration file or the QR code.

Ubuntu Linux and Unraid

On Ubuntu Linux (for more details, see https://ubuntu.com/server/docs/introduction-to-wireguard-vpn):
sudo apt install wireguard sudo mkdir -p /etc/wireguard sudo nano /etc/wireguard/wg0.conf # place peer.conf content obtained from wg_easy, then save file sudo wg-quick up wg0 # will return something similar to: # [#] ip link add wg0 type wireguard # [#] wg setconf wg0 /dev/fd/63 # [#] ip -4 address add 10.10.10.2/24 dev wg0 # [#] ip link set mtu 1420 up dev wg0 # [#] resolvconf -a wg0 -m 0 -x # [#] ip -4 route add 10.10.10.0/24 dev wg0 ip -4 -brief a # to obtain the list all network interfaces configured for IPv4 on the host # a wg0 entry will be listed
On Unraid, in Settings -> VPN Manager, select Import Tunnel and give it the .conf file obtained. The adapt the configuration to reflect the Peer type of access and following the content seen in the peer .conf file:
Larger image
Larger image
After confirming with Done you can select the Inactive toggle (top right) and should see an indicator of connection (blinking red dot) on the left of the peer’s name, and other indicators of active connection such as up and down bandwidth, and traffic stats if those are enabled.
notion image
After adding more peers, you can test pinging peers to confirm the peer-to-peer component is functional.

Potential next steps…

Because our peers are able to communicate with one another, we now have another means of reaching services hosted on our infra.
If you own 3x domains, you can set up 3x instances of a similar Traefik with automatic service discovery and Homepage with docker labels on multiple instances setup, one for each subnet:
  • domain1: LAN only access (192.168.22.0/24)
  • domain2: Tailscale access (100.64.0.0/10)
  • domain3: wg_easy access (10.10.10.0/24)

Further reading

Revision History

  • 20241012-0: Initial Release
  • 20240921-0: Initial Draft