This commit is contained in:
2026-09-18 20:39:06 +02:00
parent b3c3cc38f0
commit f7b12bc7cd
24 changed files with 1474 additions and 240 deletions
+94
View File
@@ -0,0 +1,94 @@
# Hosting your web apps on mars
You can run web apps as containers and publish them on the home network at
`http://mars.sol/<name>/`, without anyone changing mars's configuration.
Everything below takes effect immediately — no restart, no redeploy.
This file is mounted read-only and is rewritten on every restart. Save what
you need from it to your memory.
## How it fits together
- `podman` in your shell does not run containers next to you. It talks,
through `$CONTAINER_HOST`, to a separate unprivileged account on mars
(`luna-apps`). Containers there keep running when you restart, and come
back after mars reboots if they were started with `--restart=always`.
- Caddy on mars routes `http://mars.sol/<name>/` to the port you name in
`/opt/data/sites/<name>.json`. A service on mars checks that file and
writes the outcome to `/opt/data/sites-status.txt`.
## Publish an app
1. Put the source under `/opt/data/apps/<name>/` with a `Containerfile` (or
`Dockerfile`), and build it. The directory is uploaded, so this works from
where you are:
podman build -t localhost/<name> /opt/data/apps/<name>
2. Run it. Publish its port on `127.0.0.1` only, using a host port between
@portMin@ and @portMax@ that no other app uses (`podman ps` shows the
taken ones):
podman run -d --name <name> --restart=always \
-p 127.0.0.1:20001:8080 localhost/<name>
3. Register it:
echo '{"port": 20001}' > /opt/data/sites/<name>.json
4. Check that it took, then fetch it:
cat /opt/data/sites-status.txt
curl -si http://127.0.0.1/<name>/
It is now at `http://mars.sol/<name>/` for anyone on the home network.
## Rules the registry enforces
- `<name>` is lowercase letters, digits and `-`, starts with a letter or
digit, at most 32 characters. The file is `/opt/data/sites/<name>.json`.
- The file holds exactly one JSON object, and only `port` is read.
- `port` is an integer from @portMin@ to @portMax@. Anything else is rejected
(that includes everything else already running on mars).
- A rejected entry never affects the others. `sites-status.txt` says why.
- If `sites-status.txt` starts with `ERROR`, that is a fault on mars's side,
not in your entry — tell darman.
## Writing apps that work under /<name>/
Caddy strips `/<name>` before the request reaches your app, so the app itself
sees `/`, `/style.css`, `/api/items`. The browser, however, is at
`http://mars.sol/<name>/`, so every link, asset URL and fetch() in the page must
keep that prefix:
- Prefer relative URLs: `style.css`, `./api/items` — not `/style.css`.
- Or set the framework's public base URL to `/<name>/` (e.g. Vite's `base`).
Avoid settings that ALSO expect the prefix on incoming requests (Next.js
`basePath`); the prefix has already been removed by then.
- The original prefix arrives in the `X-Forwarded-Prefix` header.
- `http://mars.sol/<name>` redirects to `http://mars.sol/<name>/`.
## Files and data
- `-v /opt/data/...:/somewhere` does not work: those paths exist only inside
your container, and `luna-apps` cannot see your files. Copy code into the
image in the `Containerfile`.
- Keep an app's state in a named volume: `-v <name>-data:/data`.
- Pulling public images works (`podman pull docker.io/library/nginx`).
- Do not copy tokens or anything else from `/opt/data` into an app. The apps
cannot read your files; keep it that way.
## Update, inspect, remove
- Update: rebuild, `podman rm -f <name>`, run it again on the same port. The
JSON file stays as it is.
- Inspect: `podman ps -a`, `podman logs <name>`, `cat /opt/data/sites-status.txt`.
- Remove: `rm /opt/data/sites/<name>.json`, then `podman rm -f <name>`, and
optionally `podman rmi localhost/<name>` and `podman volume rm <name>-data`.
## Limits
- Home network only: plain `http://`, not reachable from the internet, not on
mgaction.town.
- There is no login in front of these apps. Anyone on the home network can
use them, so do not publish anything that would be a problem to expose there.