Secure Your VPS Services with WireGuard: A Complete Guide to Site-to-Site VPN with Uptime Kuma Monitoring
- Sascha Kuhlmann

- Jan 17
- 5 min read
Updated: Jan 18
I joined last year the Xandeum Crypto Community and became overnight a pNode-Owner. Xandeum's goal is to provide a storage layer on top of the Solana blockchain

The Problem
As an owner of a tiny fraction of this ecosystem, I am responsible to make sure my pNodes are up and running. Instead of constantly logging into the different servers via SSH i was looking for a way to make sure that the servers are up and running. So on a long weekend i was looking into how to connect my local network with the different VPS Servers and to monitor them not only from a technical connectivity (e.g ping the server) but to ensure that the services running on the VPS are actually responding correctly when they are called.
One service in the Xandeum Stack (aka pod.service) has an RPC endpoint that's bound to 127.0.0.1:6000. This is a common security practice—services listening only on localhost can't be accessed from the internet. But what if you need to access these services from your home network?
The traditional solutions have drawbacks:
Opening ports to the internet — Security nightmare
SSH tunnels — Manual setup every time, not persistent
Exposing services on public IPs — Increases attack surface
The better solution? A site-to-site WireGuard VPN between my home router and the VPS. This creates an encrypted tunnel where my entire home network can securely access VPS services as if they were local.
Architecture Overview

Key components:
Home Router acts as WireGuard server (192.168.40.1)
Contabo VPS acts as WireGuard client (192.168.40.11)
socat relays traffic from the VPN interface to localhost services
Uptime Kuma monitors the RPC endpoint through the VPN tunnel
Firewall installed on the VPS - i use ufw in this example
Prerequisites:
A VPS (I'm using Contabo, but any provider works)
A home router that supports WireGuard (or a dedicated Linux box) - i use a Unifi Dream Machine SE
Root/sudo access on the VPS side as well admin rights on your router
Basic familiarity with Linux command line
A internet provider who does not use CGNAT (if so you need a static IP)
Part 1: Setting up the Wireguard on your home router
On the Home Router (Server) - for Unifi
On your Unifi Console go to System Settings > VPN > VPN Server and select "Create New"

Make sure you to select your WAN IP
Select Manual so you can define your own Subnet for the VPN
Define the VPN IP Subnet - 192.168.10.255
Select "Add Client" to add your first client

5. Enter a name for your new client e.g. Pnode Test
If you want to select your the IP you want to use for this client, if not, Unifi will pick the first available

Enter the custom IP for your VPS Client (192.168.40.11)
Download the client configuration file for your new client to your desktop
Congrats you configured the Server side for your wireguard VPN!
The file should look like this - please do not share you public IP and the keys in this files with anyone, in order to prevent a security breach

Part 2: Installing WireGuard on your VPS
Log into your VPS via SSH
On the VPS (Ubuntu/Debian)
sudo apt update
sudo apt install wireguardPart 3: Configuring the VPS (WireGuard Client)
Create a new configuration file for your Wireguard client:
sudo nano /etc/wireguard/wg0.confPaste the configuration file into the created conf file:
[Interface]
PrivateKey = <VPS_PRIVATE_KEY>
Address = 192.168.40.11/24
[Peer]
# Home Router
PublicKey = <HOME_ROUTER_PUBLIC_KEY>
AllowedIPs = 192.168.40.1/32, 192.168.10.0/24
Endpoint = <HOME_ROUTER_PUBLIC_IP>:51821
PersistentKeepalive = 25
Please make sure you append the line
PersistentKeepalive = 25to the config file and also adjust the line AllowedIPs to your specific setup
AllowedIPs = 192.168.40.1/32, 192.168.1.0/24
Configuration breakdown:
AllowedIPs includes both the router's VPN IP AND your home LAN subnet (192.168.1.0/24)—this allows return traffic to reach your home devices
Endpoint — Your home router's public IP address
PersistentKeepalive — Sends a packet every 25 seconds to keep the connection alive through NAT
Enable and Start
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0Verify the Connection
# Check interface status
sudo wg show
# Test connectivity from VPS to home router
ping 192.168.40.1Part 4: The socat Relay — Exposing Localhost Services
Here's the clever part. The Xandeum pod RPC service only listens on 127.0.0.1:6000 and I can't change that. But I can use socat to relay traffic from the VPN interface to localhost.
Install socat
sudo apt install socatTest It Manually
socat TCP-LISTEN:6000,bind=192.168.40.11,fork,reuseaddr TCP:127.0.0.1:6000This tells socat to:
Listen on the VPN IP (192.168.40.11) port 6000
Forward all traffic to localhost:6000
Fork for multiple connections
Reuse the address if restarted
Make It Permanent with systemd
Create /etc/systemd/system/rpc-relay.service:
[Unit]
Description=RPC Relay via socat
After=network.target wg-quick@wg0.service
[Service]
Type=simple
ExecStart=/usr/bin/socat TCP-LISTEN:6000,bind=192.168.40.11,fork,reuseaddr TCP:127.0.0.1:6000
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now rpc-relayVerify It's Running
ss -tlnp | grep 6000You should see:
LISTEN 0 1024 127.0.0.1:6000 *:* users:(("pod",...))
LISTEN 0 5 192.168.40.11:6000 *:* users:(("socat",...))Part 5: Configuring UFW Firewall
Don't forget the firewall! UFW needs to allow traffic from the VPN subnet.
# Allow WireGuard traffic
sudo ufw allow 51820/udp
# Allow RPC access from VPN subnet only
sudo ufw allow from 192.168.40.0/24 to any port 6000 proto tcp
# Verify
sudo ufw statusThe beauty of this setup is that port 6000 is only accessible from the VPN subnet—it's not exposed to the public internet.
Part 6: Testing from local network
From any device on your home network, you should now be able to access the VPS service - Attention this is specific to the Xandeum Pod software - if you have a different use case you need to adjust the following commands:
curl -X POST http://192.168.40.11:6000/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "get-version",
"id": 1
}' | jqCommon Pitfalls - if it times out, check:
Ping the VPS from the local network (ping 192.168.40.11)
Ping the Wireguard server from the VPS (ping 192.168.40.1)
WireGuard is running on both ends (sudo wg show)
socat is listening (ss -tlnp | grep 6000)
UFW rules are in place (sudo ufw status)
Part 7: Monitoring with Uptime Kuma
Now that the RPC is accessible over the VPN, let's monitor it with Uptime Kuma..
Deploy Uptime Kuma (Docker Compose)
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
ports:
- "3001:3001"
volumes:
- uptime-kuma-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
volumes:
uptime-kuma-data:Start it:
docker compose up -dAccess the web UI at http://your-server:3001 and create an admin account.
Configure the RPC Monitor
Click Add New Monitor
Monitor Type: HTTP(s) - JSON Query
Method: POST
Body:
{
"jsonrpc": "2.0",
"method": "get-version",
"id": 1
} Headers: Add Content-Type: application/json
JSON Query: $.jsonrpc (or $.result to check the actual response)
Expected Value: 2.0
Uptime Kuma will now POST to your RPC endpoint every minute (configurable) and alert you if it goes down.
Congratulations you can now monitor your pNode remotely and create dashboards like this:

Next Steps for me
I will continue to further build out my Monitoring network - uptime-kuma is awesome for simple heartbeat monitoring. But i am also keen on monitoring CPU, Memory Utilization as well Diskspace.
Stuff for a future Blog.



Comments