Solel//dev docs

Back ends and workers

A back end is a container Solel runs for your app while it's turned on. It can serve your front end, keep the app's data, and reach people's things through the core.

In the manifest

"backend": {
  "image": "ghcr.io/example/notes@sha256:…",
  "port": 8080,
  "health": "/healthz"
}

The image is pinned by digest, and the server downloads it from its registry, so put it somewhere your server can reach. health is a path that answers 200 while the app is well.

What the container gets

Variable What it is
PORT The port from the manifest. Listen on it
SOLEL_DATA /data, the app's own volume
SOLEL_CORE_URL The core's address on the apps network
SOLEL_APP_TOKEN The app's own token. Send it to the core as Authorization: Bearer <token>. It works only while the app is installed and turned on, and only for what its grants allow
SOLEL_GPU amd or nvidia, with the gpu.use grant on a server with a card to share

Health and restarts

  • Health. Every 10 seconds Solel asks the health path and expects 200. A new container has a minute to start answering.
  • Restarts. A container that stops, or stays unhealthy, is started again. After 3 restarts in 10 minutes, Settings › Apps says it stopped working and Solel leaves it down until someone chooses Try again, a new image comes with an update, or its internet or graphics card grant changes.
  • Can't start. An image that can't be downloaded or started shows as Couldn't start, and Solel tries again every little while.

Network, graphics card and data

  • Network. Back ends share an apps network that can't reach the internet. With network.internet they can. Changing that grant replaces the container.
  • Graphics card. With gpu.use, on a server set up for its card (see Graphics cards), the back end gets it: amd at /dev/dri for Vulkan, OpenCL and video, or nvidia for CUDA. Without a card to share, SOLEL_GPU is unset, so fall back to the CPU. The card is shared with Solel's own models, so load little and let it go when you're done.
  • Data. /data is kept when the app is updated or removed, so installing it again picks up where it left off, unless whoever removes it deletes what it saved too. An app installed for one person has a volume of its own for them.
  • Locked down. Containers run with every capability dropped, no-new-privileges and at most 512 processes.

Logs

What the back end writes to standard output and standard error is kept, the newest 1,000 lines, for admins to read in Settings › Health. Write one JSON object a line, with level and msg, to keep levels and details. Never log what people wrote, their files or their mail.

Who's asking

Requests Solel passes to your back end, from the app's window or its own address, say who's using it in X-Solel-User (their Solel id), X-Solel-Username, X-Solel-Name and X-Solel-Role. Other apps' containers can reach your back end directly and send headers of their own, so every request from Solel also carries X-Solel-Proxy-Token, set to your SOLEL_APP_TOKEN. Trust the identity headers only when it matches, compared in constant time:

func fromSolel(r *http.Request) bool {
	token := os.Getenv("SOLEL_APP_TOKEN")
	got := r.Header.Get("X-Solel-Proxy-Token")
	return token != "" && subtle.ConstantTimeCompare([]byte(got), []byte(token)) == 1
}

Safe mode

In safe mode every back end stops and app tokens are refused, until an admin leaves it. See Health and safe mode.

Workers

Workers are containers a back end starts for each person, like the Browser's, which runs a real browser for everyone who uses it. Only Solel's own apps can have them: a manifest from anyone else with backend.workers is refused.