# Hosting your web apps on mars You can run web apps as containers and publish them on the home network at `http://mars.sol//`, 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//` to the port you name in `/opt/data/sites/.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//` with a `Containerfile` (or `Dockerfile`), and build it. The directory is uploaded, so this works from where you are: podman build -t localhost/ /opt/data/apps/ 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 --restart=always \ -p 127.0.0.1:20001:8080 localhost/ 3. Register it: echo '{"port": 20001}' > /opt/data/sites/.json 4. Check that it took, then fetch it: cat /opt/data/sites-status.txt curl -si http://127.0.0.1// It is now at `http://mars.sol//` for anyone on the home network. ## Rules the registry enforces - `` is lowercase letters, digits and `-`, starts with a letter or digit, at most 32 characters. The file is `/opt/data/sites/.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 // Caddy strips `/` before the request reaches your app, so the app itself sees `/`, `/style.css`, `/api/items`. The browser, however, is at `http://mars.sol//`, 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 `//` (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/` redirects to `http://mars.sol//`. ## 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 -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 `, run it again on the same port. The JSON file stays as it is. - Inspect: `podman ps -a`, `podman logs `, `cat /opt/data/sites-status.txt`. - Remove: `rm /opt/data/sites/.json`, then `podman rm -f `, and optionally `podman rmi localhost/` and `podman volume rm -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.