How to Self-Host Netmaker with Docker Compose

What Is Netmaker?

Netmaker is a WireGuard-based networking platform that creates and manages virtual overlay networks. Unlike Tailscale or Headscale which use userspace WireGuard, Netmaker uses kernel WireGuard by default for near-native throughput. It supports multiple isolated networks from a single deployment, has a built-in web dashboard, managed DNS via CoreDNS, and features like egress gateways, relay servers, and ACLs. The Community Edition is open source under SSPL.

Updated March 2026: Verified with latest Docker images and configurations.

Prerequisites

  • A Linux server with a static public IP (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 2 GB of RAM (1 GB minimum, 2 GB recommended)
  • A domain name with wildcard DNS capability
  • Ports 443 (TCP+UDP), 51821-51830 (UDP) open on your firewall
  • A domain name (required — used for API, dashboard, and MQTT broker)

DNS Setup

Netmaker requires three subdomains. Create these DNS records before deploying:

RecordTypeValue
api.nm.yourdomain.comAyour-server-ip
dashboard.nm.yourdomain.comAyour-server-ip
broker.nm.yourdomain.comAyour-server-ip

Or use a single wildcard record: *.nm.yourdomain.comyour-server-ip

Docker Compose Configuration

Create a docker-compose.yml file:

services:
  netmaker:
    image: gravitl/netmaker:v1.5.0
    container_name: netmaker
    restart: unless-stopped
    depends_on:
      - mq
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    environment:
      SERVER_NAME: ${NM_DOMAIN}
      SERVER_HOST: ${SERVER_PUBLIC_IP}
      SERVER_API_CONN_STRING: api.${NM_DOMAIN}:443
      STUN_LIST: "stun1.l.google.com:19302,stun2.l.google.com:19302"
      MQ_HOST: mq
      MQ_PORT: "1883"
      MQ_SERVER_PORT: "443"
      DNS_MODE: "on"
      CORS_ALLOWED_ORIGIN: "*"
      DISPLAY_KEYS: "on"
      DATABASE: sqlite
      NODE_ID: netmaker-server
      VERBOSITY: "1"
      MASTER_KEY: ${MASTER_KEY}
    volumes:
      - netmaker-sqldata:/root/data
      - netmaker-dnsconfig:/root/config/dnsconfig
    ports:
      - "51821-51830:51821-51830/udp"

  netmaker-ui:
    image: gravitl/netmaker-ui:v1.5.0
    container_name: netmaker-ui
    restart: unless-stopped
    depends_on:
      - netmaker
    environment:
      BACKEND_URL: https://api.${NM_DOMAIN}

  caddy:
    image: caddy:2.11.2
    container_name: netmaker-caddy
    restart: unless-stopped
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_conf:/config
    ports:
      - "80:80"
      - "443:443"
    environment:
      NM_DOMAIN: ${NM_DOMAIN}

  mq:
    image: eclipse-mosquitto:2.0.15-openssl
    container_name: netmaker-mq
    restart: unless-stopped
    volumes:
      - ./mosquitto.conf:/mosquitto/config/mosquitto.conf
      - mosquitto_data:/mosquitto/data
      - mosquitto_logs:/mosquitto/log
    environment:
      NETMAKER_SERVER_HOST: https://api.${NM_DOMAIN}

  coredns:
    image: coredns/coredns:1.10.1
    container_name: netmaker-coredns
    restart: unless-stopped
    command: -conf /root/dnsconfig/Corefile
    volumes:
      - netmaker-dnsconfig:/root/dnsconfig
    ports:
      - "53:53/udp"
      - "53:53/tcp"

volumes:
  caddy_data:
  caddy_conf:
  netmaker-sqldata:
  netmaker-dnsconfig:
  mosquitto_data:
  mosquitto_logs:

Create a .env file:

# Your domain — subdomains api., dashboard., broker. must resolve to this server
NM_DOMAIN=nm.yourdomain.com

# Your server's public IP address
SERVER_PUBLIC_IP=203.0.113.1

# Master API key — generate with: openssl rand -hex 32
MASTER_KEY=change-me-generate-with-openssl-rand-hex-32

Create a Caddyfile for the reverse proxy:

{
    email [email protected]
}

# Dashboard
dashboard.{$NM_DOMAIN} {
    reverse_proxy netmaker-ui:80
}

# API
api.{$NM_DOMAIN} {
    reverse_proxy netmaker:8081
}

# MQTT WebSocket
broker.{$NM_DOMAIN} {
    reverse_proxy mq:1883
}

Create a mosquitto.conf for the MQTT broker:

per_listener_settings true
listener 1883
allow_anonymous true

Start the stack:

docker compose up -d

Initial Setup

  1. Open https://dashboard.nm.yourdomain.com in your browser
  2. Create your admin account on the first visit
  3. Create a network:
    • Name: home (or whatever you prefer)
    • Address range: 10.10.10.0/24
    • Default settings for everything else
  4. Add your first node using the enrollment key generated in the dashboard

Installing Netclient on Nodes

On each device you want to add to the network:

# Install netclient
curl -sL 'https://apt.netmaker.org/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/netclient.asc
curl -sL 'https://apt.netmaker.org/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/netclient.list
sudo apt update && sudo apt install netclient

# Join a network using the enrollment key from the dashboard
netclient join -t <enrollment-token>

Configuration

Egress Gateway

Route traffic from the Netmaker network to external networks (your LAN, the internet):

  1. In the dashboard, select a node
  2. Click “Create Egress”
  3. Set the egress range (e.g., 192.168.1.0/24 for your LAN)
  4. The selected node becomes the gateway — all other nodes can now reach your LAN through it

Relay Server

If nodes can’t connect directly (strict NAT, firewalls), set up a relay:

  1. Select a publicly reachable node in the dashboard
  2. Click “Create Relay”
  3. Select which nodes should relay through it
  4. Traffic flows: Node A → Relay → Node B (encrypted WireGuard throughout)

Access Control

Netmaker supports network-level ACLs:

  1. Go to Networks → your network → ACLs
  2. Toggle connections between specific nodes on/off
  3. Nodes with ACL disabled can’t communicate even though they’re on the same WireGuard network

Reverse Proxy

Caddy is included in the Docker Compose stack and handles SSL automatically via Let’s Encrypt. No additional reverse proxy configuration is needed unless you want to put Netmaker behind an existing Nginx Proxy Manager or Traefik setup.

If using an external reverse proxy, remove the Caddy service and proxy these internal services:

SubdomainTargetPort
dashboard.nm.yourdomain.comnetmaker-ui80
api.nm.yourdomain.comnetmaker8081
broker.nm.yourdomain.commq1883 (WebSocket)

Backup

Back up the SQLite database and DNS config:

# Stop Netmaker first to ensure consistent backup
docker compose stop netmaker

# Back up the data volume
docker run --rm -v netmaker-sqldata:/data -v $(pwd):/backup alpine tar czf /backup/netmaker-data.tar.gz /data

# Restart
docker compose start netmaker

See our Backup Strategy guide for automated approaches.

Troubleshooting

Nodes Can’t Connect to Server

Symptom: netclient join fails or nodes show as disconnected in the dashboard.

Fix: Verify ports 443 (TCP+UDP) and 51821 (UDP) are open. Check that your DNS records resolve correctly: dig api.nm.yourdomain.com. Ensure the MQTT broker is running: docker logs netmaker-mq.

Dashboard Shows 502

Symptom: https://dashboard.nm.yourdomain.com returns a 502 error.

Fix: Check if the netmaker-ui container is running: docker logs netmaker-ui. Verify the BACKEND_URL in the UI container matches your actual API domain. Check Caddy logs: docker logs netmaker-caddy.

DNS Not Resolving Device Names

Symptom: <device>.<network> hostnames don’t resolve.

Fix: Ensure CoreDNS is running and port 53 isn’t already taken by systemd-resolved:

# Check if port 53 is in use
sudo ss -ulnp | grep :53

# If systemd-resolved is blocking port 53
sudo systemctl disable --now systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

High CPU from Netclient

Symptom: The netclient agent uses excessive CPU.

Fix: Update to the latest netclient version. Older versions had polling loops that caused high CPU. Also check if the node is acting as a relay for many peers — relay nodes do more work.

Resource Requirements

  • RAM: ~500 MB idle (server + UI + Caddy + MQTT + CoreDNS), ~1 GB under load
  • CPU: Low-Medium (WireGuard key exchange is the main CPU consumer)
  • Disk: ~200 MB for application, plus SQLite database growth
  • Network: Static public IP required. Wildcard DNS or 3 subdomain A records.

Verdict

Netmaker is the most feature-rich self-hosted networking platform — kernel WireGuard performance, multiple isolated networks, a built-in dashboard, managed DNS, egress gateways, relay servers, and ACLs. The trade-off is complexity: 5 containers, wildcard DNS setup, custom netclient agent (not standard WireGuard/Tailscale clients), and SSPL licensing. If you need multiple isolated networks or near-native WireGuard throughput, Netmaker is the best choice. If you want simplicity with standard Tailscale clients, Headscale is far easier to deploy. For the simplest mesh networking setup, Tailscale (cloud) or NetBird (self-hosted) are better options.

FAQ

How does Netmaker compare to Headscale (Tailscale)?

Headscale uses userspace WireGuard via standard Tailscale clients — simple setup, broad device support (iOS, Android, macOS, Windows, Linux). Netmaker uses kernel WireGuard for higher throughput but requires its own netclient agent. Netmaker offers multiple isolated networks, egress gateways, and relay servers. Choose Headscale for simplicity; choose Netmaker for maximum performance and advanced network features. See Headscale vs Netmaker.

Why does Netmaker need a domain name?

Netmaker uses three subdomains for its API, web dashboard, and MQTT broker. SSL certificates are required for secure communication between the server and netclient agents. A domain with wildcard DNS (*.nm.yourdomain.com) is the simplest setup.

Can I use Netmaker with standard WireGuard clients?

No. Netmaker requires its own netclient agent, not standard WireGuard or Tailscale clients. The netclient handles automatic key rotation, network updates, and server communication. If you want to use standard WireGuard configs, use plain WireGuard. For Tailscale client compatibility, use Headscale.

Can Netmaker create separate networks for different purposes?

Yes. This is a key differentiator — Netmaker supports multiple isolated WireGuard networks from a single deployment. Create a “home” network for personal devices, a “work” network for business, and a “lab” network for testing. Nodes only communicate within their assigned network unless explicitly bridged.

Is Netmaker truly open source?

The Community Edition is under the Server Side Public License (SSPL), which is not OSI-approved. SSPL allows use but restricts offering Netmaker as a managed service. For personal and business self-hosting, SSPL imposes no practical limitations. The Professional Edition is proprietary.

Does Netmaker work on mobile devices?

Android support exists through the netclient agent. iOS support is limited — there’s no native iOS netclient, so iOS devices can’t join Netmaker networks directly. For iOS support, use Headscale with the official Tailscale iOS app.

Comments