Protect NOMAD with Caddy + basicauth

Put a username and password in front of NOMAD's admin pages when you expose your box past localhost. Community-verified config, free Let's Encrypt TLS, five steps.

Looking for the regular install? See the main install guide.

Community-supported, not official

NOMAD is intentionally designed without authentication for local single-user use. Putting a reverse proxy with basicauth in front is a network-level workaround, not a NOMAD feature. You take on the security responsibility for any config you run. If you hit issues, post in GitHub Discussions rather than opening a bug report against the install script.

This is a security risk

Do not do this if you don't understand what you're doing.

A misconfigured reverse proxy can expose your entire NOMAD instance — settings, content, AI assistant, admin APIs — to the open internet. A typo in the Caddyfile, a router rule that forwards too much, or a weak password can hand attackers the keys. If you can't read the steps below and explain back to yourself what each one is doing, stop here. Run NOMAD on localhost only and come back when you're comfortable.

Who this is for

You're running NOMAD on a home or small-office LAN, and you want to keep other people on the network from changing settings, restarting services, or fiddling with installed content. Maybe you've given the URL out to family members, or you want to put NOMAD behind a real domain name with HTTPS.

This is not for exposing NOMAD directly to the public internet. NOMAD wasn't designed for hostile traffic. A basic auth gate is a speed bump, not a firewall — don't treat it as one.

What this does (and doesn't do)

Does

  • • Requires a username and password to reach /settings and the admin API surface
  • • Auto-provisions and renews a Let's Encrypt cert if you point a real domain at the box
  • • Lets you expose Command Center on a single port without forwarding 8080 directly

Doesn't

  • • Encrypt content at rest or add per-user accounts (NOMAD has no user model)
  • • Protect Kiwix, Kolibri, CyberChef, or FlatNotes — those run on their own ports and stay open on the LAN
  • • Make NOMAD safe for the public internet

Set it up

Five steps on the same Linux box that's running NOMAD.

1. Install Caddy

On Ubuntu or Debian:

sudo apt update
sudo apt install caddy

2. Generate a password hash

Caddy doesn't store passwords in plain text. Generate a bcrypt hash to paste into the config:

$ caddy hash-password

You'll be prompted to type the password twice. Copy the hash that prints — you'll need it in step 4.

3. Open the Caddyfile

$ sudo nano /etc/caddy/Caddyfile

4. Replace its contents with this config

<domain>:<port> {

    reverse_proxy localhost:8080

    @protected {
        path /settings/*
        path /api/settings/*
        path /api/system/*
        path /api/docker/*
        path /api/jobs/*
        path /api/services/*
    }

    basicauth @protected {
        <user> <hash>
    }
}

Then fill in the four placeholders:

  • <domain> — your domain name (e.g. nomad.example.com), or leave blank / use your public IP if you don't have one
  • <port> — the port you want Caddy to listen on (e.g. 8081, or leave blank to use the standard 80/443)
  • <user> — the username you want to log in with
  • <hash> — the hash you generated in step 2

The @protected matcher gates the admin UI and the underlying admin APIs (/api/settings, /api/system, /api/docker, /api/jobs, /api/services) so an attacker can't skip the UI and just curl the API directly. Don't trim that list.

You don't need to forward port 8080 on your router — Caddy reverse-proxies to it from localhost. Forward only the port Caddy is listening on. If you used a real domain, Caddy will reach out to Let's Encrypt and provision a TLS cert automatically.

5. Restart Caddy

$ sudo systemctl restart caddy

Visit your domain (or IP) on the port you chose. The first time you hit a protected route, your browser will show a basic-auth prompt.

Verify it's working

The bypass to watch for is hitting an admin API directly without going through the UI. Test it from another machine on your network:

$ curl -i -X POST http://<domain>:<port>/api/settings/write

You should get back HTTP/1.1 401 Unauthorized with a www-authenticate: Basic realm="restricted" header. If you get anything else (200, 404, 500), the matcher isn't covering that route — re-check that you copied the @protected block in full.

Re-run with -u user:password and you should get a non-401 response (likely a 404 from an empty body — that's fine, it confirms auth passed).

Three gotchas to know about

1. Several login prompts on first page load

Command Center makes background API calls when it boots. Until you've authenticated, the browser will fire a basic-auth prompt for each one — you'll see roughly four prompts in a row on the first visit. You can either log in once (and the browser will hold the credentials for the rest of the session) or hit Cancel on each prompt and still use the non-admin tools. Hitting the Settings menu later will surface another prompt; that's expected.

2. In-app links to Kiwix / Kolibri / CyberChef / FlatNotes won't pass through the proxy

NOMAD's home screen builds those tile links from the hostname your browser used plus the app's own port (e.g. http://nomad.example.com:8090 for Kiwix). Caddy is only reverse-proxying port 8080, so those links won't resolve from outside your LAN. Workaround: launch the apps from inside the LAN where the per-app ports are reachable, or proxy each app separately on its own subdomain (out of scope for this guide).

3. The threat model is "trusted LAN with a gate," not "public internet"

Even with this config, the home page, the AI chat, the knowledge base, and every content browser remain open. An attacker on the same network can still load and download content, hammer the AI with requests, and consume disk and CPU. Putting NOMAD on a public IP — even with this proxy — is asking for trouble. If you need real public access, put NOMAD behind a VPN like Tailscale or WireGuard instead.

Community credit

The Caddyfile above is @Zacharyprime's work, originally proposed in PR #767. They expanded the @protected matcher to cover the admin API surfaces (closing a bypass where an attacker could hit /api/settings/* directly without authenticating) and verified end-to-end against a real NOMAD instance with the curl test shown above. Thanks Zachary.

Get help

Hit a problem this guide doesn't cover? Post in GitHub Discussions with your Caddy version, the relevant chunk of your Caddyfile (with secrets redacted), and the exact response you're getting.

Please don't open bug reports against the install script for proxy-related issues — reverse proxies aren't officially supported, and we can't triage every Caddy / nginx / Traefik configuration.