Skip to main content

WebUI Deployment

The OxiDNS WebUI is a separately built static frontend. It is not compiled into the Rust backend binary. There are two recommended deployment modes:

  • Backend-hosted WebUI: the OxiDNS management HTTP service serves the WebUI static directory directly. This is the simplest path for bare-metal hosts, NAS boxes, and small servers without nginx.
  • Standalone nginx deployment: nginx serves the WebUI static files and reverse-proxies /api/* to the OxiDNS backend. This is better for environments that already use a domain, HTTPS, a gateway, or a shared service entry point.

In both modes, the WebUI defaults to the relative backend URL /api. When the WebUI page and /api/* share the same browser origin, no CORS setup is needed.

Use The WebUI Included In Release Packages​

Official release archives include a prebuilt webui/ directory:

oxidns
config.yaml
LICENSE
webui/

When OxiDNS runs from the extracted release directory, the default webui.root: "./webui" config works directly. Docker images also place the same WebUI static files under /etc/oxidns/webui.

Debian packages install the service with -c /etc/oxidns/config.yaml -d /var/lib/oxidns. Therefore the default webui.root: "./webui" means /var/lib/oxidns/webui, which the post-install step links to /usr/share/oxidns/webui.

Manual WebUI builds are only needed when building from source, developing the WebUI, or publishing static files separately through nginx or caddy.

Build The WebUI Manually​

The WebUI lives in the repository's webui/ directory. Production builds are exported to webui/out:

cd webui
pnpm install --frozen-lockfile
pnpm build

After building, publish out/ to a server directory, for example:

sudo mkdir -p /etc/oxidns/webui
sudo rsync -a --delete out/ /etc/oxidns/webui/

The examples below use /etc/oxidns/webui as the static directory.

Mode 1: Backend-Hosted WebUI​

This mode only needs the OxiDNS management HTTP port. The WebUI is mounted at /, and the management API is mounted under /api/*.

api:
http:
listen: "0.0.0.0:9199"
auth:
type: basic
username: "admin"
password: "secret"
webui:
root: "/etc/oxidns/webui"
index: "index.html"

Then open:

http://server-ip:9199/

The WebUI calls same-origin endpoints such as /api/health, /api/config, and /api/plugins/.... Static files are not protected by Basic Auth; all /api/* requests still use the management API authentication, CORS, and TLS rules.

Field notes:

  • api.http.webui.root
    • WebUI static file directory. This requires the expanded api.http form.
    • Relative paths resolve against OxiDNS -d/--working-dir, not against the configuration file directory.
    • The shorthand api.http: "ip:port" only configures the listen address and cannot mount WebUI files.
  • api.http.webui.index
    • Index file name. Defaults to index.html.
    • /, directory paths, and unmatched frontend deep links fall back to this file.

Static serving behavior:

  • /api and /api/* always go to the management API and never fall back to the WebUI.
  • Non-API GET/HEAD requests look up static files.
  • Unmatched non-API paths return index.html, so refreshing frontend routes such as /settings works.
  • The backend rejects path traversal attempts such as .., absolute paths, and invalid percent-decoded paths.

Mode 2: Standalone nginx Deployment​

In this mode, OxiDNS listens only on a local management API address, and nginx exposes the WebUI plus /api proxy externally.

OxiDNS can use a simple API-only config:

api:
http:
listen: "127.0.0.1:9199"
auth:
type: basic
username: "admin"
password: "secret"

nginx example:

server {
listen 80;
server_name oxidns.example.com;

root /etc/oxidns/webui;
index index.html;

location = /api {
proxy_pass http://127.0.0.1:9199;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /api/ {
proxy_pass http://127.0.0.1:9199;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

location / {
try_files $uri $uri/ /index.html;
}
}

Here proxy_pass http://127.0.0.1:9199; forwards browser requests such as /api/health to the backend unchanged. Do not use a form that strips the /api prefix. The OxiDNS backend only accepts API routes under /api/*.

If nginx terminates HTTPS, add listen 443 ssl, certificates, and the HTTP-to-HTTPS redirect in nginx. The OxiDNS backend can keep listening on plain 127.0.0.1:9199 because it is not exposed publicly.

WebUI Backend URL​

Keep the WebUI backend URL at the default value:

/api

This works for:

  • Backend-hosted WebUI.
  • nginx, caddy, or another gateway proxying /api/* to OxiDNS.
  • Docker Compose setups with a single entry container for WebUI and API.

Only use an absolute URL for development or temporary debugging, for example:

http://192.168.1.10:9199/api

Absolute URLs trigger browser CORS rules, so the backend must allow the WebUI origin. The default CORS inference is:

  • listen: "0.0.0.0:9199" or listen: "[::]:9199" allows any origin.
  • Listening on a specific IP allows any WebUI port on the same host.
  • When api.http.cors.allowed_origins is configured explicitly, entries are matched exactly against the browser Origin.

Use The Online Console With A Local Service​

You can also open https://console.oxidns.org and set the backend URL in the WebUI settings page to the OxiDNS management API on your machine or LAN:

http://127.0.0.1:9199/api

If the browser and OxiDNS are not on the same machine, use the reachable address instead, for example:

http://192.168.1.10:9199/api

This is not the recommended deployment mode. The online Console page and the local API are different origins, so the browser enforces CORS; the management API must also be reachable from the browser. Prefer backend-hosted WebUI or an nginx/caddy reverse proxy so the WebUI and /api/* stay same-origin.

If you still need the online Console for temporary use, explicitly allow the Console origin:

api:
http:
listen: "127.0.0.1:9199"
cors:
allowed_origins:
- "https://console.oxidns.org"

When accessing the OxiDNS management API from another device, also change listen to a LAN IP or 0.0.0.0:9199, and restrict access with a firewall, reverse-proxy authentication, or network policy. Do not expose an unprotected management API directly to the public internet.

Common Checks​

  • Opening http://server:9199/ or the nginx domain shows the WebUI.
  • Browser Network shows /api/health returning 200, not a static file.
  • If Basic Auth is enabled, configure the same username and password in the WebUI settings page.
  • If refreshing /settings or /plugins returns 404, the static server is missing the index.html fallback. For nginx, check try_files $uri $uri/ /index.html;.
  • If /api/health returns 404 through nginx, check whether proxy_pass accidentally strips the /api prefix.