SnapRAID UI controls your array and runs with wide access to the host, so anyone who can use it can do a lot of damage. This page explains the built-in login, how to run behind a reverse or authentication proxy, and what you should and shouldn't expose.
Treat access to SnapRAID UI like root access to your server:
- It runs SnapRAID commands that write to your disks, including
fixand undelete. - Its API reads and writes files by path inside the container, which runs as root. The config editor and file browser rely on this.
- In the recommended setup the container is privileged, which gives processes in it broad access to the host's devices.
So: never expose SnapRAID UI directly to the internet. Keep it on your home network, or reach it through a VPN (WireGuard, Tailscale) or a reverse proxy with HTTPS and authentication.
The login is turned on by setting both environment variables:
environment:
- SNAPRAID_UI_USERNAME=admin
- SNAPRAID_UI_PASSWORD=a-long-random-passwordIf either one is missing, the login is off and the UI is open to anyone who can reach it. The backend logs Login disabled at startup in that case, and Login enabled for user "<name>" when it is on.
With the login on, every API request and the WebSocket need a valid session; without one the backend answers 401 Unauthorized and the browser shows the login page. There is one user, with the credentials from the environment. Passwords are compared in constant time, and a wrong username takes as long to reject as a wrong password.
For Podman, the Quadlet unit reads the password from a Podman secret instead of plain text, see Installation.
After signing in, the browser gets a session cookie:
| Property | Value |
|---|---|
| Name | snapraid_session |
| Contents | A signed token (JWT, HS256) with the username and expiry |
| Lifetime | SNAPRAID_UI_SESSION_HOURS, default 168 hours (7 days) |
| Flags | HttpOnly, SameSite=Strict, Path=/; Secure when the request arrived over HTTPS (see below) |
Sessions are not stored on the server. The token is signed with a key made of the random .session-secret in the data directory and a hash of the username and password. That means:
- Sessions survive restarts and updates.
- Changing the username or password ends all sessions.
- Deleting
.session-secretand restarting the container also ends all sessions. - Log out (at the bottom of the sidebar) deletes the cookie in that browser. A copy of the token stays valid until it expires, so if you suspect a session was stolen, change the password.
When a session expires, the next request sends you back to the login page.
To slow down password guessing:
- Every failed login waits half a second before it answers.
- After 5 failed attempts, further logins from the same client address are refused for the rest of a 15-minute window that starts with the first failure. The login page shows a countdown (Too many failed attempts. Try again in …).
- A successful login resets the counter for that address.
The counters are kept in memory, so restarting the container clears them.
The client address comes from the X-Real-IP header that the container's own Nginx sets to the address of whoever connected to it. Behind a reverse proxy, that is the proxy, so all users share one counter: five wrong passwords from anyone lock everyone out for up to 15 minutes. Restart the container if that locks you out.
A reverse proxy is the usual way to add HTTPS. Set it up as described in Installation, and keep these points in mind:
- Only the proxy should reach the container. Bind the port to localhost (
127.0.0.1:3000:80) or use a shared Docker network without publishing a port. - Publish only port 80 of the container. The backend also listens on port 8080 inside the container. Don't publish it: requests to it bypass the container's Nginx, so a client could set its own
X-Real-IPheader and escape the lockout. - The
Securecookie flag is not set behind a proxy. The container's Nginx passes on the protocol of its own connection, which is plain HTTP from your proxy, so the backend can't tell that the browser used HTTPS. The cookie is stillHttpOnlyandSameSite=Strict. Configure your proxy to redirect HTTP to HTTPS, so the browser never sends the cookie unencrypted.
If you already run an authentication proxy such as Authelia, Authentik or oauth2-proxy, you can leave the built-in login off and let the proxy handle sign-in:
- Remove
SNAPRAID_UI_USERNAMEandSNAPRAID_UI_PASSWORD. - Make sure the container is reachable only through the proxy (see above). With the login off, anyone who reaches the container port directly has full access.
- Protect the whole host name, including
/apiand/ws.
Without the built-in login, the sidebar shows no user and no Log out button.
The browser sends the session cookie only with requests from SnapRAID UI itself (SameSite=Strict), and the backend allows cross-origin requests with credentials only from pages on the same host name (such as the development frontend on another port). Together, this keeps other websites you visit from acting with your session.
Everything lives in the data directory, see Configuration. Security-relevant files:
| File | Contents | Protection |
|---|---|---|
.session-secret |
Key that signs sessions | Created with file mode 600 |
notifications.json |
Notification settings, including the SMTP password and ntfy token | Plain text. The API never sends them back to the browser; the form shows a placeholder instead. |
config.json, schedules.json, histories |
Settings and disk data | Plain text |
logs/ |
SnapRAID output, including file names from your disks | Plain text |
The login password itself is never written to disk; it only exists in the environment of the container.
A backup from Download backup contains the notification passwords and tokens in plain text. Keep backup files private.
- Login enabled with a long, random password, or an authentication proxy in front
- Not reachable from the internet, or only through a VPN or an HTTPS proxy
- Only container port 80 published, and only to the proxy if you use one
- Data directory and backup files readable only by you
-
--privilegedonly if you need SMART data (see Installation)