Documentation
Virtual hosts
Every HTTP backend serves on virtual hosts: the names clients put in the URL.
One vhost carries several backends at once — a calendar, an address book, a
file share and a website on jens.dev, for example. Each backend owns its
own part of the host, and Everlock checks those parts against each other
whenever a vhost is added or changed.
Paths and the fallback
A vhost is divided into two kinds of part:
- Paths. A backend owns a path prefix, such as
/caldav, with every request at or below it. A prefix covers whole path segments:/caldavcovers/caldavand/caldav/calendars/work/, and leaves/caldavxand/davto others. - The fallback. One backend owns everything on the host outside the paths: the pages of a website, a photo gallery, the git web UI.
A request goes to the backend owning the path that covers it, else to the
backend owning the host's fallback, else it gets 404.
The rules for one vhost:
- Paths on one host are disjoint.
/caldavand/caldav/extraoverlap, so only one of them exists on a host;/davand/davx, or/davand/caldav, sit side by side. - A host has one fallback, owned by one backend instance; a second backend asking for it is refused.
- Paths and the fallback sit side by side; a path takes its requests ahead of
the fallback. That includes paths the fallback backend serves itself: the
photo gallery answers the Immich API at
/api, and the vault the Bitwarden API at/apiand/identity, so the admin dashboard and API, which own/api, belong on a host without either. /.well-known/acme-challengebelongs to the HTTP frontend on every host, where it answers the certificate challenges.
What each backend owns
The backend type decides what it owns. You only say which instance serves on which vhost.
| Backend | Kind | Owns on each of its vhosts |
|---|---|---|
| Calendar | path | /caldav, /.well-known/caldav |
| Contacts | path | /carddav, /.well-known/carddav |
| Files | path | the share's mount, /dav by default |
| MCP | path | /mcp |
| Admin dashboard and API | path | /admin, /api |
| OCI registry | path | /v2 |
| OAuth / OIDC | path | /oauth, /.well-known/openid-configuration, /.well-known/jwks.json |
| Site | fallback | everything else |
| Images | fallback | everything else |
| Git web UI | fallback | everything else, on the git.http.vhost host |
| Vault | fallback | everything else |
Within one backend a vhost belongs to one instance: one calendar instance per host, one file share per host, one site per host.
Sharing a vhost
Calendar, contacts, a file share and the MCP endpoint on jens.dev, with a
website for everything else:
/site create website vhost=jens.dev
/calendar create family vhost=jens.dev
/contacts create family vhost=jens.dev
/files create docs vhost=jens.dev
/server settings set admin.mcp.vhost jens.dev
jens.dev then serves:
https://jens.dev/caldav/… /.well-known/caldav → calendar instance 'family'
https://jens.dev/carddav/… /.well-known/carddav → contacts instance 'family'
https://jens.dev/dav/… → file share 'docs'
https://jens.dev/mcp → admin MCP endpoint
https://jens.dev/… everything else → site 'website'
The order of the commands is free: each one checks only what it adds.
A photo gallery wants the fallback of its host, and the site holds that of
jens.dev, so adding one there is refused:
> /image create photos vhost=jens.dev
error: the fallback of jens.dev is held by site 'website' — see https://everlock.sh/docs/vhosts
Give the gallery a host of its own:
/image create photos vhost=photos.jens.dev
A path that overlaps one in use is refused the same way, naming the path and its owner — here a share's mount moved into the calendar's space:
> /files set docs mount=/caldav/docs
error: `/caldav` on jens.dev is held by calendar instance 'family' — see https://everlock.sh/docs/vhosts
A mount beside the others, such as mount=/files, is taken.
The same check covers every command that adds or changes a vhost:
create and set for /calendar, /contacts, /files (a new mount
included), /site, /image, /oci and /vault, and
/server settings set for admin.http.vhost, admin.mcp.vhost,
git.http.vhost and oauth.http.vhost. A refused command saves nothing.
Hand-edited configuration
A config file edited by hand can give two backends the same path or the same fallback. At start the backend that comes up first keeps it — backends start in a fixed order, so it is the same one on every start. The other backend serves its remaining vhosts and logs the vhost it leaves out, with the owner and the overlapping path:
backend-image-http: vhost 'jens.dev' of image instance 'photos' is not served: the fallback of jens.dev is held by site 'website'
/server log shows these lines. Moving one of the two instances to another
vhost with its set and unset commands resolves it.
Certificates and mDNS
A vhost that any backend serves gets its ACME certificate and its HTTPS
redirect once, whatever number of backends share it, and a .local vhost is
announced over mDNS once. When the last backend leaves a vhost, the vhost
leaves the certificate renewal, the redirect and the mDNS announcement at
once.