Website Hosting Restricted to WireGuard Private Network

8 min

language: ja bn en es hi pt ru zh-cn zh-tw

Hello, I'm incompetent.
It's not ideal for admin pages to be publicly exposed, but in my case, I currently only allow WireGuard private IPs for admin pages. Here's how to set that up.

WireGuard Configuration

This means I'm using multiple clients.

Client Side

In this case, for wg0, since AllowedIPs = 0.0.0.0/0, ::/0, all traffic passes through the WireGuard network.
However, in this case, you need to write a rule on the server side to allow 10.1.0.22 to pass through the server's NAT. This is because, otherwise, this IP cannot exit the WireGuard private network.
To summarize simply, it's like this:

  • wg0
    • Passes all network traffic
    • Queries internal DNS
    • Cannot exit without a NAT rule on the WireGuard server side
  • wg1
    • Routes only WireGuard private IPs
      • Only passes traffic within the 10.1.0.0/24 CIDR range
    • Queries internal DNS

wg0.conf :

[Interface]
PrivateKey = Client Private Key
Address = 10.1.0.22/24
DNS = 10.1.0.1

[Peer]
PublicKey = Server PubKey
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = WireGuard Server Endpoint:51820
PreSharedKey = PreSharedKey

wg1.conf :

[Interface]
PrivateKey = Client Private Key
Address = 10.1.0.21/24
DNS = 10.1.0.1

[Peer]
PublicKey = Server PubKey
AllowedIPs = 10.1.0.0/24
Endpoint = WireGuard Server Endpoint:51820
PreSharedKey = PreSharedKey

Server Side

[Interface]
ListenPort = 51820
Address = 10.1.0.1/24
PrivateKey = Server PrivKey

~~~

[Peer]
PublicKey = Client PubKey
PreSharedKey = PreSharedKey
AllowedIPs = 10.1.0.21/32
PersistentKeepalive = 25

[Peer]
PublicKey = Client PubKey
PreSharedKey = PreSharedKey
AllowedIPs = 10.1.0.22/32
PersistentKeepalive = 25

This is how it looks.

WireGuard Server NAT Rules

This is a BSD-specific privilege, but I'll write the NAT rules using pf.

# Variable definition
wireguard_clients="{ 10.1.0.4, 10.1.0.22 }"
wanint="vtnet0"
wg_ports="{51820}"

# Rewrite traffic coming from $wireguard_clients to the IP of the WAN interface ($wanint) and send it to the internet
# NAPT configuration
nat on $wanint inet from $wireguard_clients to any -> $wanint

# Allow WireGuard connections (UDP 51820) coming from outside to the WAN side
pass in on $wanint proto udp from any to $wanint port $wg_ports

This allows WireGuard's private IPs themselves to pass through the WireGuard server's NAT.

Nginx Configuration

a.soulminingrig.com is the setting for the LumeCMS admin page itself on this site.
It allows only the WireGuard network with allow 10.1.0.0/16; and denies all others with deny all;.

server {
    listen 80;
    server_name a.soulminingrig.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name a.soulminingrig.com;
    client_max_body_size 500M;

    location / {
        allow 10.1.0.0/16;
	    deny all;

        proxy_pass http://10.1.0.20:3001/;
        include proxy_headers.conf;
        proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504 http_403 http_404;
        proxy_connect_timeout 3s;
        proxy_read_timeout 15s;
    }
    include common_error_pages.conf;
    include ssl_common.conf;

    ssl_certificate /usr/local/etc/letsencrypt/live/a.soulminingrig.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /usr/local/etc/letsencrypt/live/a.soulminingrig.com/privkey.pem; # managed by Certbot
}

Why can IP restrictions be applied without being recognized as the WireGuard server's Public IP, even though NAT rules are written?

You might have this question. (I made it up myself)

The NAT rule is written like this:

nat on $wanint inet from $wireguard_clients to any -> $wanint

In other words, on $wanint means that NAT is applied only to packets passing through the WAN interface.
It's a bit complicated, but let's try ifconfig to make it clearer.

vtnet0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
        options=4c079b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,TXCSUM_IPV6>
        ether aa
        inet aa netmask 0xfffffe00 broadcast aa
        inet6 aa prefixlen 64 scopeid 0x1
        inet6 aa prefixlen 64
        media: Ethernet autoselect (10Gbase-T <full-duplex>)
        status: active
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
        inet 127.0.0.1 netmask 0xff000000
        inet6 ::1 prefixlen 128
        inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
        groups: lo
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
pflog0: flags=0 metric 0 mtu 33152
        options=0
        groups: pflog
wg0: flags=10080c1<UP,RUNNING,NOARP,MULTICAST,LOWER_UP> metric 0 mtu 1420
        options=80000<LINKSTATE>
        inet 10.1.0.1 netmask 0xffffff00
        groups: wg
        nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>

Yes, WireGuard is ultimately a virtual NIC, so the interface in the case of WireGuard is wg0.
In this case, since it comes through wg0, if proxy_pass is set to 10.1.0.20:3001, packets will pass through this virtual NIC.

10.1.0.22 -> matches the rule allow 10.1.0.0/16 (10.1.0.0 to 10.1.255.255) -> Nginx's proxy_pass is 10.1.0.20, so it completes within the private network.
During this time, everything is completed within the virtual NIC on wg0, enabling this private communication.

Conclusion

So, what do you think?
Honestly, I personally dislike writing rules in GNU/Linux, so BSD's pf is incredibly easy in this sense...
See you next time. Thank you.

Related Posts