CallMeTechie
DE Login
Home Products Blog About Contact

First Home Gateway Setup

🚀 Installation & Setup · Updated 1 month ago

You have a NAS, a mini PC or a Raspberry Pi in your home network and want to make services on it (router admin, NAS WebUI, Home Assistant, …) reachable through your GateControl instance. Without port forwarding on the router, without detours.

The solution is the home gateway container (ghcr.io/callmetechie/gatecontrol-gateway): a slim companion that builds an outbound WireGuard tunnel to the server and acts as a forwarder in the LAN. The server proxy can then reach any LAN target via target_kind=gateway, and the gateway performs the final hop.

This guide takes you through it once: create peer → pull gateway.env → docker-compose on the NAS → check the first heartbeat.

Duration: ~10 minutes.


What you need beforehand

  • A running GateControl instance with a Pro license (home gateway is a Pro feature).
  • Admin access to the GateControl web UI.
  • A host machine in the home network running Docker. Typical candidates:
    • Synology DSM 7.2+ with Container Manager
    • Raspberry Pi 4/5 with Raspberry Pi OS
    • Ubuntu/Debian box
    • Proxmox LXC with nesting + keyctl
  • /dev/net/tun must be available on the host (the compose template below passes it through explicitly). On Synology and some LXC variants a one-off modprobe tun has to run for this.
  • A free LAN IP on the gateway host and access to the LAN segment of the target devices. Important: the gateway host must physically be in the same Layer 2 network as the devices you want to reach — otherwise Wake-on-LAN won't work.

No port forward on the router, no firewall opening, no public IP needed. The tunnel goes from the gateway to the server over UDP 51820.


1. Create the gateway peer in the admin UI

  1. Open the admin UI and go to Peers & Clients.
  2. Click on + Add (top right).
  3. In the modal:
    • Peer Name: e.g. homeserver-nuc or nas-syno — that's the display name in the admin UI.
    • Description (optional): Intel NUC · Debian 12 · living room.
    • Tick Home Gateway. The Gateway API Port field appears and stands at 9876. Leave the default, as long as the port on the host is not already occupied.
  4. Click Save.

After saving, the UI shows a one-off dialog with the pairing tokens (api_token and push_token). The tokens are shown in plaintext only this one time — the server only stores hashes. Leave the modal open until step 2.


2. Download gateway.env

In the same dialog there is a Download gateway config button.

The file is called gateway.env and contains everything the gateway container needs:

GC_SERVER_URL=https://gate.example.com
GC_API_TOKEN=...
GC_GATEWAY_TOKEN=...
GC_TUNNEL_IP=10.8.0.42
GC_API_PORT=9876
GC_HEARTBEAT_INTERVAL_S=30
WG_PRIVATE_KEY=...
WG_PRESHARED_KEY=...
WG_ENDPOINT=gate.example.com:51820
WG_SERVER_PUBLIC_KEY=...
WG_ADDRESS=10.8.0.42/32
WG_ALLOWED_IPS=10.8.0.1/32
WG_DNS=10.8.0.1

Important:

  • Save the file immediately in a password manager or directly on the gateway host.
  • If you lose the .env: open peer edit → click Download ENV again. This rotates both tokens — the old gateway loses the connection and must be redeployed.
  • WG_ADDRESS=10.8.0.42/32 is deliberately a /32 (not /24). That prevents routing conflicts if in parallel on the same machine a normal GateControl client is running.

3. docker-compose on the gateway host

On the NAS/Pi/NUC create a folder, e.g. /opt/gatecontrol-gateway/.

Inside docker-compose.yml:

services:
  gateway:
    image: ghcr.io/callmetechie/gatecontrol-gateway:latest
    container_name: gatecontrol-gateway
    restart: unless-stopped
    network_mode: host
    cap_drop:
      - ALL
    cap_add:
      - NET_ADMIN         # wg-quick, iptables, Routing
      - NET_BIND_SERVICE  # L4-Ports <1024 (SSH, DNS, HTTP)
    read_only: true
    user: "0:0"
    devices:
      - /dev/net/tun:/dev/net/tun
    tmpfs:
      - /tmp
      - /run
      - /etc/wireguard
    volumes:
      - ./config:/config:ro
    environment:
      - LOG_LEVEL=info
      - GATEWAY_ENV_PATH=/config/gateway.env
      - WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

Explanations of the most important points:

  • network_mode: host is mandatory. The gateway binds L4 routes dynamically on changing ports — that wouldn't work with Docker NAT without restart.
  • cap_drop: ALL + two explicit caps is the security baseline. NET_ADMIN is needed by wg-quick, NET_BIND_SERVICE only if you run L4 routes on ports < 1024.
  • read_only: true with tmpfs for /tmp, /run, /etc/wireguard — wg-quick writes config at runtime into /etc/wireguard.
  • user: "0:0" is deliberately root: wg-quick is a shell script (line 85) that goes nowhere if UID != 0. The security boundary is the caps, not the UID.
  • WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go forces the userspace WireGuard implementation. On Synology DSM and in LXC containers without a WG kernel module, that's the only way.

Then put the gateway.env from step 2 into ./config/gateway.env (i.e. next to the compose file, in a config/ subfolder).

mkdir -p config
mv ~/Downloads/gateway.env config/gateway.env
chmod 600 config/gateway.env

4. Start the container

docker compose up -d
docker compose logs -f gateway

In the first few seconds you'll see:

  • WG setup ([#] ip link add wg0 type wireguard …)
  • Heartbeat message: POST /api/v1/gateway/heartbeat → 200
  • config sync: version N applied

Give the process ~30 seconds until the first heartbeat.


5. Check in the admin UI

Back in the admin UI, on Peers & Clients. In the Home Gateways section your gateway card should now appear with a green status dot as Online.

Click on the card — in the detail panel you see:

  • Last seen (should be seconds ago)
  • WG handshake (time, fresh)
  • Uptime + container version (from gateway_info.section_version)
  • Routed targets (still empty — you create routes in the next step)

6. Create the first gateway route

As soon as the gateway is online, you can add LAN hosts as a route. That is the standard case: HTTP route on e.g. dsm.example.com → target_kind gateway → select gateway peer → LAN host 192.168.1.10:5001 → done.

Detailed walkthrough with all fields and DNS/TLS subtleties: see adding-a-route.md.

For Remote Desktop access to Windows machines in the same LAN: see configuring-rdp.md.


Troubleshooting

Gateway stays offline

  1. Look at the container logs:

    docker compose logs --tail 200 gateway
    

    Typical messages:

    • GC_SERVER_URL unreachable → DNS/network from the gateway to the server broken.
    • 401 unauthorized → tokens in gateway.env don't match the DB. Tokens rotated or wrong .env placed?
    • TLS alert 80 → server has an SSL problem; see certificates.md.
  2. Simulate the heartbeat via curl from the gateway host:

    curl -i -X POST https://gate.example.com/api/v1/gateway/heartbeat \
         -H "Content-Type: application/json" \
         -H "Authorization: Bearer $(grep ^GC_GATEWAY_TOKEN config/gateway.env | cut -d= -f2)" \
         -d '{"peer_id":42,"status":"ok"}'
    

    200 OK → network is good, problem lies in the container code. Connection refused / timeout → firewall/DNS.

  3. Check .env for corruption (e.g. Windows line endings after copy-paste via Windows tools):

    file config/gateway.env
    # should say "ASCII text", not "CRLF"
    

WG tunnel doesn't come up

Symptom: logs show wg-quick: not a valid key or Handshake did not complete after 5 seconds.

Check steps:

  1. Server endpoint reachable? From the gateway host: nc -u -v gate.example.com 51820 (must be UDP — nc without -u is TCP and says "open" although UDP is closed).
  2. GC_BASE_URL set correctly in the server? If the gateway.env comes with placeholder domain gatecontrol.example.com, you haven't set GC_BASE_URL in the server .env.
  3. Firewall between gateway host and internet: UDP 51820 outbound must be free. ICMP is not a sufficient test.
  4. /dev/net/tun present?
    docker exec -it gatecontrol-gateway ls -la /dev/net/tun
    
    If "No such file or directory": run modprobe tun on the host and restart the container.

Config hash out of sync

Symptom: new route in the admin UI does not appear in the gateway.

Cause: gateway uses pull + push sync. Push comes from the server (OK), pull every GC_POLL_INTERVAL_S seconds (default 300 = 5 min).

Fix: in the admin UI trigger Reload on the gateway card — calls the push endpoint directly. Alternatively once docker compose restart gateway.

"Port 9876 already in use"

The health API port (GC_API_PORT in the gateway.env) collides with something else on the host. Edit the peer in the admin UI, set a different port (e.g. 19876), re-download .env.


Further reading

Cookie Settings

We use cookies to improve your experience. Essential cookies are always active.

Privacy Policy
ESC
↑↓ navigate open esc close