Secure Remote Access to a Homelab with WireGuard

As Realm Labs grew, remote access became increasingly useful.

There are plenty of services inside the lab that I normally access only from the local network: management interfaces, dashboards, shared resources and other internal systems. That is fine when I am at home, but much less useful when I am away and need to check something.

I did not want to solve that by forwarding a collection of management ports directly through the router.

Instead, I wanted one secure route back into the network.

WireGuard became the VPN solution for that job.

The original version of this article explained the basic idea, but the important part is how WireGuard actually fits into a homelab: routing, peers, internal addressing and deciding what remote devices should be allowed to reach.

What I Wanted to Achieve

The requirement was simple:

Remote Device
     |
     | Encrypted connection
     v
WireGuard VPN
     |
     v
Realm Labs Network
     |
     +-- Internal services
     +-- Management interfaces
     +-- Servers
     +-- NAS
     +-- Home Assistant

Once connected, a remote device should be able to reach selected internal systems in much the same way as if it were connected to the home network.

The goals were:

  • secure remote access
  • no direct exposure of internal management ports
  • individual configuration for each remote device
  • the ability to revoke one device without affecting the others
  • simple enough configuration that I could still understand it six months later

Why WireGuard?

WireGuard is a lightweight VPN protocol that works particularly well for this kind of setup.

The main reasons I like it are:

  • straightforward configuration
  • good performance
  • small number of moving parts
  • support across Windows, Linux, Android and iOS
  • public-key authentication
  • easy peer management

It does not require a complicated user database or certificate infrastructure for a small homelab deployment.

Each device has its own cryptographic identity.

That makes the model easy to understand:

WireGuard Server
     |
     +-- Laptop Peer
     |
     +-- Phone Peer
     |
     +-- Admin Device Peer

Understanding the WireGuard Model

WireGuard configuration is based around interfaces and peers.

The server has:

  • its own private key
  • its own public key
  • a VPN IP address
  • a listening UDP port

Each client has:

  • its own private key
  • its own public key
  • its own VPN IP address

The server knows the public key of each authorised client.

The client knows the public key of the server.

Private keys stay private.

Planning the VPN Address Range

Before configuring WireGuard, it is worth choosing a dedicated subnet for VPN clients.

For example:

Home LAN:
192.168.68.0/24

WireGuard VPN:
10.10.10.0/24

The WireGuard server could then use:

10.10.10.1

while clients use addresses such as:

Laptop
10.10.10.2

Phone
10.10.10.3

Tablet
10.10.10.4

Keeping the VPN on its own subnet makes routing and troubleshooting much easier.

Installing WireGuard

On a Debian-based Linux host, WireGuard can be installed with:

sudo apt update
sudo apt install wireguard -y

Once installed, the configuration is normally stored under:

/etc/wireguard/

A common interface name is:

wg0

which gives a configuration file of:

/etc/wireguard/wg0.conf

Generate the Server Keys

WireGuard uses public and private key pairs.

Generate the server keys with:

wg genkey | tee server_private.key | wg pubkey > server_public.key

You can then view them with:

cat server_private.key

and:

cat server_public.key

The private key should be protected.

Do not publish it or include it in screenshots.

Basic Server Configuration

A simple server configuration might look like this:

[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

Save this as:

/etc/wireguard/wg0.conf

Then restrict access to the file:

sudo chmod 600 /etc/wireguard/wg0.conf

Enable IP Forwarding

A VPN server needs to forward traffic between the WireGuard network and the LAN.

On Linux, check the current IPv4 forwarding state with:

sysctl net.ipv4.ip_forward

To enable it temporarily:

sudo sysctl -w net.ipv4.ip_forward=1

To make it persistent, add this to:

/etc/sysctl.conf
net.ipv4.ip_forward=1

Then apply the configuration:

sudo sysctl -p

Without forwarding, the client may connect successfully to WireGuard but still be unable to reach anything beyond the VPN server itself.

That distinction is important.

Starting the WireGuard Interface

Bring the interface up with:

sudo wg-quick up wg0

Check its status:

sudo wg

You should see information including:

  • interface public key
  • listening port
  • configured peers
  • latest handshake
  • transfer statistics

To stop it:

sudo wg-quick down wg0

Start WireGuard Automatically

Enable the VPN interface at boot:

sudo systemctl enable wg-quick@wg0

Start it with:

sudo systemctl start wg-quick@wg0

Check the service:

sudo systemctl status wg-quick@wg0

Creating the First Client

Generate a separate key pair for the client.

For example:

wg genkey | tee laptop_private.key | wg pubkey > laptop_public.key

The important rule is:

One device
    |
    +-- One key pair
    +-- One VPN IP
    +-- One peer entry

I do not reuse one client configuration across multiple devices.

Separate peers make management much cleaner.

Add the Client to the Server

Add the client’s public key to wg0.conf.

For example:

[Peer]
PublicKey = LAPTOP_PUBLIC_KEY
AllowedIPs = 10.10.10.2/32

The /32 means that this peer owns one specific VPN address:

10.10.10.2

A second device might use:

[Peer]
PublicKey = PHONE_PUBLIC_KEY
AllowedIPs = 10.10.10.3/32

This makes it easy to identify devices later.

Client Configuration

A basic client configuration might look like:

[Interface]
PrivateKey = LAPTOP_PRIVATE_KEY
Address = 10.10.10.2/24
DNS = 192.168.68.20

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = vpn.example.com:51820
AllowedIPs = 192.168.68.0/24, 10.10.10.0/24
PersistentKeepalive = 25

Replace the hostname and addresses with the values used by your own network.

What AllowedIPs Actually Does

AllowedIPs is one of the most important WireGuard settings.

On the client, it effectively tells WireGuard:

Send traffic for these networks through the VPN.

For example:

AllowedIPs = 192.168.68.0/24

means only traffic destined for the home LAN is sent through WireGuard.

Normal internet traffic continues through the client’s normal internet connection.

This is known as split tunnelling.

Split Tunnel or Full Tunnel?

There are two common approaches.

Split Tunnel

Only traffic for the home network goes through the VPN.

For example:

AllowedIPs = 192.168.68.0/24, 10.10.10.0/24

The flow becomes:

Realm Labs traffic
      |
      +--> WireGuard

Everything else
      |
      +--> Normal internet connection

This is generally what I prefer for homelab administration.

Full Tunnel

All traffic goes through the VPN:

AllowedIPs = 0.0.0.0/0

The flow becomes:

Everything
    |
    v
WireGuard
    |
    v
Home Network
    |
    v
Internet

This can be useful when using untrusted public networks, but it also means the home connection carries all of the client’s traffic.

Routing to the Home LAN

A successful WireGuard handshake does not automatically mean the client can reach the rest of the home network.

Traffic has to be routed correctly.

The overall path is:

Remote Laptop
10.10.10.2
     |
     v
WireGuard Server
10.10.10.1
     |
     v
Home LAN
192.168.68.0/24

This is where many VPN configurations go wrong.

The encrypted tunnel itself works, but the network behind it does not know what to do with the VPN client’s traffic.

NAT as the Simple Approach

One way to solve this is NAT or masquerading on the WireGuard server.

For example, using iptables:

sudo iptables -t nat -A POSTROUTING \
  -s 10.10.10.0/24 \
  -o eth0 \
  -j MASQUERADE

This makes traffic from VPN clients appear to the home LAN as though it came from the WireGuard server itself.

That is often the easiest option for a small homelab.

The downside is that internal systems no longer see the original VPN client address.

Routing Without NAT

A cleaner network design is to teach the main router how to reach the VPN network.

Conceptually:

Destination:
10.10.10.0/24

Gateway:
WireGuard server LAN IP

The LAN can then route directly back to VPN clients.

This preserves the real VPN client addresses and gives more control over firewall rules.

Whether this is practical depends on the capabilities of the router and network design.

DNS Over the VPN

If I want remote clients to access systems using internal hostnames rather than raw IP addresses, the VPN client also needs access to internal DNS.

For example:

DNS = 192.168.68.20

This means a connected client may be able to resolve internal names such as:

seido.order.realm

instead of needing:

192.168.68.20

That is much nicer to work with.

It also reduces the number of hard-coded IP addresses I need to remember.

Public Endpoint

The client needs some way to find the WireGuard server from the internet.

That normally means:

Public IP

or:

DNS hostname

For example:

Endpoint = vpn.example.com:51820

Using a hostname is preferable if the public IP can change.

Dynamic DNS can then keep the hostname pointed at the current address.

Router Configuration

WireGuard normally listens on UDP port:

51820

If the WireGuard server sits behind a normal home router, the router needs to forward that UDP port to the WireGuard host.

Conceptually:

Internet
    |
UDP 51820
    |
Router
    |
Port Forward
    |
WireGuard Server

This should be one deliberate VPN port, not dozens of individual management interfaces.

Why This Is Better Than Forwarding Everything

Without a VPN, remote access can easily become:

Port 8080 -> App 1
Port 3000 -> App 2
Port 9443 -> Portainer
Port 8123 -> Home Assistant
Port 22   -> SSH

I do not like that design.

With WireGuard:

Internet
    |
UDP 51820
    |
WireGuard
    |
Authenticated VPN Client
    |
Internal Services

The internal applications do not need to be individually exposed.

Device-Specific Peers

Each device has its own peer configuration.

For example:

Laptop
    |
10.10.10.2

Phone
    |
10.10.10.3

Tablet
    |
10.10.10.4

This provides a useful security benefit.

If I lose a device, I can remove only that peer from the server.

The rest of the VPN remains unchanged.

Revoking a Device

If a client should no longer have access, remove its peer entry from the WireGuard server configuration.

Then restart or reload WireGuard.

The key belonging to that device will no longer be accepted.

That is much cleaner than changing one shared VPN password used by every device.

Testing the Tunnel

Once the client connects, start with the simplest tests.

Check WireGuard

On the server:

sudo wg

Look for a recent:

latest handshake

If there is no handshake, there is no point troubleshooting internal routing yet.

Ping the VPN Server

From the client:

ping 10.10.10.1

If this works, the encrypted tunnel itself is functioning.

Ping a LAN Device

Next try an internal address:

ping 192.168.68.20

If the VPN server responds but the LAN device does not, the problem is probably:

  • forwarding
  • routing
  • firewall
  • NAT

rather than WireGuard authentication.

Test an Actual Service

Finally test something useful.

For example:

https://internal-dashboard

or:

\\seido\Share

or an internal SSH/RDP connection.

That confirms the full path rather than just ICMP connectivity.

Useful Troubleshooting Order

I find it easier to work through WireGuard problems in layers.

1. Does WireGuard start?
        |
2. Does the client handshake?
        |
3. Can the client reach the VPN server?
        |
4. Can the client reach the LAN?
        |
5. Does DNS work?
        |
6. Can the required application be reached?

This is much better than changing five firewall and routing settings at once.

Check the WireGuard Status

On the server:

sudo wg

Useful information includes:

latest handshake
transfer
endpoint
allowed ips

If the handshake is recent and transfer counters are increasing, the encrypted part of the connection is probably working.

Firewall Considerations

A remote VPN does not mean every connected device should automatically have unrestricted access to everything.

It is worth thinking about what the VPN client actually needs.

For example:

VPN Client
     |
     +--> Home Assistant
     +--> Synology
     +--> Proxmox
     +--> SSH
     X
     +--> Other networks

The more segmented the network becomes, the more useful explicit firewall rules become.

Keep WireGuard Updated

The server should be treated like any other internet-facing system.

That means:

  • keep the operating system patched
  • keep WireGuard updated
  • remove unused peer configurations
  • review firewall rules
  • monitor unusual behaviour
  • protect the server’s private key

Remote access is useful precisely because it creates a path into the internal network.

That path deserves attention.

Do Not Share Private Keys

WireGuard does not work like a normal username and password service.

Private keys are the identity of the peer.

A configuration containing:

PrivateKey =

should therefore be treated as sensitive.

If a private key is exposed, generate a new one and replace that peer.

Remote Access and Cloudflare Tunnel

Realm Labs also uses Cloudflare Tunnel for some externally accessible web services.

That does not make WireGuard redundant.

They solve slightly different problems.

Cloudflare Tunnel works very well for publishing selected web applications.

WireGuard is more useful when I want broader network-level access.

For example:

Cloudflare Tunnel
      |
      +--> Specific web service


WireGuard
      |
      +--> Internal network access
      +--> SMB
      +--> SSH
      +--> RDP
      +--> Management interfaces

I use whichever model fits the service.

WireGuard and Remote Desktop

One useful example is Windows Remote Desktop.

Rather than exposing RDP directly to the internet, a remote machine can first join the WireGuard VPN.

The flow becomes:

Remote Laptop
      |
WireGuard
      |
Realm Labs LAN
      |
Windows PC
      |
RDP

The Windows machine itself does not require a public RDP port.

WireGuard and Synology

The same approach works for Synology storage.

Once connected to the VPN, a client can access an SMB share using the internal network path.

For example:

\\seido\Share

That is useful when I need access to files without making SMB itself internet-facing.

WireGuard and Proxmox

Management interfaces are another good use case.

I do not want the Proxmox management interface exposed directly to the public internet.

Instead:

Remote Device
      |
WireGuard VPN
      |
Internal Network
      |
Proxmox

The management interface remains internal while still being available remotely when I need it.

Monitoring Connected Peers

The wg command makes it easy to see which peers have recently connected.

For example:

sudo wg show

A peer with a recent handshake is actively communicating.

A peer that has not connected for months may be a candidate for cleanup.

As the peer list grows, giving devices sensible names in documentation becomes important.

A random public key is not particularly memorable six months later.

Document the Configuration

I keep a record of:

  • device name
  • VPN address
  • public key
  • purpose
  • date added

For example:

Device: Laptop
Address: 10.10.10.2
Purpose: Remote administration

Device: Phone
Address: 10.10.10.3
Purpose: Mobile access

Do not record private keys in general documentation unless that documentation is itself securely protected.

What I Have Learned

The biggest lesson from building remote access was that installing WireGuard itself is the easy part.

The interesting problems come from everything around it:

  • routing
  • DNS
  • firewall rules
  • network addressing
  • NAT
  • access control

A VPN can report:

Connected

while still being completely useless for accessing the network behind it.

Understanding the traffic path matters much more than simply getting a successful handshake.

Security Versus Convenience

Remote access needs to be convenient enough that I will actually use it.

But convenience should not turn into:

Expose everything
Allow everything
Forget about it

The goal is controlled access.

WireGuard provides the secure transport.

Network design still decides where that transport is allowed to take you.

The Result

WireGuard gives Realm Labs a secure route back into the network when I am away from home.

Instead of exposing individual management services directly to the internet, I can establish one encrypted VPN connection and then access internal systems through their normal private addresses.

Each remote device has its own peer, its own key pair and its own VPN address.

If a device is lost or retired, that peer can be removed without changing the rest of the setup.

Most importantly, WireGuard has made remote access feel like part of the network rather than a collection of unrelated workarounds.

That is exactly what I wanted from it.