How to Secure Self-Hosted Hermes WebUI with Password Auth and WebAuthn Passkeys
Problem
Self-hosted AI tools often ship with no authentication by default. When you bind to 0.0.0.0 or tunnel remotely, you leave the interface exposed. I needed to secure my Hermes WebUI instance before accessing it from my phone via Tailscale.
Authentication Layers
Hermes WebUI supports two authentication layers:
- Password authentication — enabled via
HERMES_WEBUI_PASSWORDenv var or the Settings panel - Passkeys / WebAuthn — registered from Settings -> System after signing in with a password
Password auth is off by default for zero-friction localhost use. Once you register at least one passkey, you can remove the password and keep passkey-only sign-in.
Enabling Password Auth
The simplest way to add protection is the environment variable:
export HERMES_WEBUI_PASSWORD=your-strong-password./start.shFor Docker deployments:
echo "HERMES_WEBUI_PASSWORD=your-strong-password" >> .envdocker compose up -d --force-recreateRemote Access Patterns
For secure remote access, I use an SSH tunnel:
ssh -N -L 8787:127.0.0.1:8787 user@your-serverIf you prefer Tailscale, bind to all interfaces and protect with a password:
HERMES_WEBUI_HOST=0.0.0.0 HERMES_WEBUI_PASSWORD=your-password ./start.shSecurity Details
All sessions use signed HMAC HTTP-only cookies with a 24-hour TTL. Security headers are set on all responses:
X-Content-Type-OptionsX-Frame-OptionsReferrer-Policy
POST body size is limited to 20MB. CDN resources are pinned with SRI integrity hashes.
Passkeys
Passkeys are same-origin and stored locally in the WebUI state directory. They are not backed by a cloud service. The password remains the bootstrap and recovery path until you explicitly choose to go passwordless.
Common Mistakes
I nearly made these mistakes when setting up remote access:
- Exposing port 8787 to the internet without any authentication — the default bind is
127.0.0.1for a reason. - Using a weak password — the env var approach is only as strong as the password you choose.
- Not understanding where passkeys are stored — they live in the WebUI state dir, not in a cloud identity provider.
Summary
In this post, I showed how to secure a self-hosted Hermes WebUI instance. The key point is that the security model is designed for self-hosters: off by default for localhost, easy to enable for remote access, and upgradeable to passwordless passkeys once you are set up. Always enable password protection before binding to 0.0.0.0 or tunneling remotely.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments