Connecting to NordVPN Dedicated IP via WireGuard on GL-iNet Mudi (GL-E5800) or other

After many hours of trial and error, I finally got my NordVPN Dedicated IP working over WireGuard on the GL-iNet Mudi router (firmware 4.x). The standard NordVPN configs from public generators do not work for Dedicated IP — you must query the NordVPN API to find the specific server station assigned to your account.
Here’s the working method.
Prerequisites
• GL-iNet Mudi (GL-E5800) with OpenWrt-based firmware
• NordVPN subscription with active Dedicated IP add-on
• A Linux/macOS machine (or SSH access to the router itself) with curl and python3 to query the API
• NordVPN Access Token from your account dashboard (NordVPN → Manual setup → Generate access token)
Step 1 — Get your WireGuard private key
NordVPN API uses Basic Auth where the username is the literal string token and the password is your access token:

curl -s -u "token:YOUR_ACCESS_TOKEN"
"https://api.nordvpn.com/v1/users/services/credentials"

Note the nordlynx_private_key field in the response. Save it.
Step 2 — Find the server assigned to your Dedicated IP
This is the critical step that most guides miss. Your Dedicated IP is tied to a specific server station, not to the generic country server.

curl -s -u "token:YOUR_ACCESS_TOKEN"
"https://api.nordvpn.com/v1/users/services" | python3 -m json.tool

Find the entry where service.identifier equals dedicated_ip. Inside details.servers you’ll see a numerical server ID — copy it.
Step 3 — Get the server endpoint and public key
Using the server ID from the previous step:

curl -s "https://api.nordvpn.com/v1/servers?filters\[servers.id\]=SERVER_ID"
| python3 -c "
import json, sys
s = json.load(sys.stdin)[0]
print('Hostname:', s['hostname'])
print('Station:', s['station'])
for t in s['technologies']:
if 'wireguard' in t.get('identifier','').lower():
for m in t.get('metadata', ):
if m['name'] == 'public_key':
print('WG PublicKey:', m['value'])
"

You’ll get the station IP (use this as Endpoint) and the server’s WireGuard public key. Use the IP directly — the hostname nordhold.net does not resolve for many country servers, including Polish ones.
Step 4 — Build the WireGuard configuration

[Interface]
Address = 10.5.0.2/16
PrivateKey = <nordlynx_private_key from Step 1>
DNS = 103.86.96.100
MTU = 1420

[Peer]
AllowedIPs = 0.0.0.0/0
Endpoint = <Station IP from Step 3>:51820
PersistentKeepalive = 25
PublicKey = <WG PublicKey from Step 3>

Important notes on the [Interface] section:
• Address is the internal tunnel address 10.5.0.2/16. Do not put your public Dedicated IP here — that’s a common mistake. The Dedicated IP is assigned server-side, based on your private key being registered to your account.
• DNS 103.86.96.100 is NordVPN’s resolver.
Step 5 — Add the configuration to Mudi

  1. Open the router admin panel at 192.168.8.1
  2. Go to VPN → WireGuard Client
  3. Create a new group (e.g. “NordVPN Dedicated IP”) and click New Group → Add Configuration
  4. Paste the config from Step 4 and save
  5. Click the toggle to connect
  6. In VPN Dashboard, confirm Global Mode is on and the kill switch is active if you want it
    Step 6 — Verify
    Visit any “what is my IP” service from a device connected to the Mudi. It should show your Dedicated IP — not a shared NordVPN address.
    Troubleshooting
    • ifup-failed immediately, no handshake — the endpoint hostname doesn’t resolve. Use the station IP directly.
    • REKEY-GIVEUP in logs — handshake reaches the server but fails. Wrong public key for that server, or you used a generic server instead of the one assigned to your Dedicated IP.
    • Connected but wrong IP shown — you’re hitting a shared exit. Re-check that the server ID from /v1/users/services matches the endpoint in your config.
    • Cloudflare blocks the API call from the router — run the curl commands from a different machine; the router’s outbound IP may be blacklisted.
    Hope this saves someone else the evening I spent on it.​​​​​​​​​​​​​​​​
1 Like

There is an error in step 3. Correct code:

curl -s "https://api.nordvpn.com/v1/servers?filters\[servers.id\]=SERVER_ID" \
  | python3 -c "
import json, sys
s = json.load(sys.stdin)[0]
print('Hostname:', s['hostname'])
print('Station:', s['station'])
for t in s['technologies']:
    if 'wireguard' in t.get('identifier','').lower():
        for m in t.get('metadata', []):
            if m['name'] == 'public_key':
                print('WG PublicKey:', m['value'])
"

Hi

Thank you for sharing the tutorial on using NordVPN Dedicated IP via WireGuard.

This will be very helpful for users with similar needs.

Hi,

I could not find the solution for wireguard with dedicated ip on internet myself, so I think that it would help other people as well.

1 Like

I’m having an issue with step 3, getting this error:

Traceback (most recent call last):
File "", line 3, in
s = json.load(sys.stdin)[0]
~~~~~~~~~~~~~~~~~~~~^^^
IndexError: list index out of range

I’m not sure what I am missing? Do you have any suggestions?

Solved - I was using the id that was with the service identifier and not the server id.

Thanks again to the OP on creating this step by step!

Clarification on Step 2 (since I can't edit the original post):

A user pointed out a common confusion in Step 2. The JSON response contains two different id fields, and you need the right one:

{
  "id": 439594579,                          ← NOT this one (service entry ID)
  "service": {
    "id": 11,                               ← NOT this one either (service type ID)
    "identifier": "dedicated_ip"
  },
  "details": {
    "servers": [
      { "id": 1002778 }                     ← THIS is the server ID you need
    ]
  }
}

Use the ID inside details.servers[].id — that's the actual NordVPN server assigned to your Dedicated IP. Plug that number into the Step 3 query.

Thanks to @jddreyer who flagged this!

If anyone is able to this with PIA Dedicated IP, I would really love to know