# Set up admin authentication The web interface is protected by a single password. With no password set, anyone who can reach the web port can change nxdns's configuration, so set one before you let other machines reach it. ## Set the password in the web interface In database mode, open **System**, type the new password into **password** and **confirm password** under **Web**, and press **Save**. The interface logs you out at once, and every other session ends with it; log back in with the new password. To change the password later, do the same again. ## Set it in the configuration file In file mode, or for a first configuration you import, put the password under `web`: ```zon .web = .{ .password = "choose-a-real-password" }, ``` nxdns stores only an argon2id hash of it, in `web.password_hash`, and never logs it. Applying the file, at the next start in file mode or with `nxdns import`, logs: ``` web authentication is now enabled ``` ### Put a hash in the file instead A configuration file kept in git or in the Nix store should not hold a plaintext password. Set the password once, then copy the hash out of an export: ```sh nxdns export | grep password ``` ``` .password = null, .password_hash = "$argon2id$v=19$m=19456,t=2,p=1$…", ``` Put that `.password_hash` line in your file in place of `.password`. The hash installs the same password without revealing it. A file that sets both fields is refused: ``` web.password: password and password_hash are both set; ambiguity in a security setting is refused ``` ### What the file's password fields do | The file says | What happens to the stored password | | --- | --- | | Neither field | Nothing. It stays as it was. | | `.password = "…"` | Sets that password. | | `.password_hash = "$argon2id$…"` | Sets the password that hash belongs to. | | `.password_hash = ""` | Removes the password and turns authentication off. | | `.password = ""` | Refused. | Leaving both fields out keeps the password, so deleting the hash line from a file before you commit it never opens the interface by accident. Turning authentication off takes the explicit empty hash, and logs: ``` web authentication is now disabled ``` ## If you have lost the password The web interface cannot help, so go through the database. Stop nxdns first: a running server keeps checking logins against the hash it read when it started. ```sh systemctl stop nxdns nxdns export --out /root/nxdns-rekey.zon ``` In the `web` section of `/root/nxdns-rekey.zon`, set `.password` to the new password and delete the `.password_hash` line, so only one password field is left: ```zon .password = "a-new-password", ``` Then load it and start again: ```sh nxdns import /root/nxdns-rekey.zon systemctl start nxdns rm /root/nxdns-rekey.zon ``` ``` imported /root/nxdns-rekey.zon ``` In file mode, change the password in your configuration file and restart instead. ## Sessions A login lasts `web.session_ttl_hours`, 24 hours by default. Sessions are kept in memory, so restarting nxdns logs everyone out. Up to 32 sessions are open at once; a 33rd login ends the one used least recently. Each login is logged with the address it came from, never with the password: ``` info(web_auth): web login accepted for 192.168.1.20:34040 warning(web_auth): web login refused for 192.168.1.20:59670 ``` Logins count against `web.api_rate_limit_per_min`, which limits how fast anyone can guess. Requests from the nxdns machine itself are exempt by default (`web.api_localhost_exempt`). ## Behind a reverse proxy A reverse proxy on the same machine connects from `127.0.0.1`, so every request it forwards would be exempt from the rate limit. List the proxy in `web.trusted_proxies`, and nxdns reads each client's real address from the `X-Forwarded-For` header the proxy adds: ```zon .web = .{ .trusted_proxies = "127.0.0.1" }, ``` The proxy must add its own entry to that header rather than pass on whatever the client sent. If it cannot, turn `web.api_localhost_exempt` off instead. The [configuration reference](../reference/configuration.md#web) lists every `web` setting.