95 lines
4.0 KiB
Markdown
95 lines
4.0 KiB
Markdown
# 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.
|