Documentation

Last updated: 2026-11-12

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: /caldav covers /caldav and /caldav/calendars/work/, and leaves /caldavx and /dav to 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. /caldav and /caldav/extra overlap, so only one of them exists on a host; /dav and /davx, or /dav and /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 /api and /identity, so the admin dashboard and API, which own /api, belong on a host without either.
  • /.well-known/acme-challenge belongs 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.

BackendKindOwns on each of its vhosts
Calendarpath/caldav, /.well-known/caldav
Contactspath/carddav, /.well-known/carddav
Filespaththe share's mount, /dav by default
MCPpath/mcp
Admin dashboard and APIpath/admin, /api
OCI registrypath/v2
OAuth / OIDCpath/oauth, /.well-known/openid-configuration, /.well-known/jwks.json
Sitefallbackeverything else
Imagesfallbackeverything else
Git web UIfallbackeverything else, on the git.http.vhost host
Vaultfallbackeverything 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.

http vhosts routing reference