Replace the four-section dir layout with the revised flat-page spec: - Three-page nav: Libraries, Standards, Deploy. - libraries.md: live client-side fetch of the rethink-public org from the Gitea API, denylist-filtered, sorted table linking each repo, no version pins, graceful fallback on fetch/CORS failure. - standards.md: house coding standards. - deploy.md: deploy guide for rethink-net (services uid 1337, uid-agnostic Docker, paths/mounts, bind-mount permissions, read-only secrets). - index.md landing card grid updated for the three sections. - gitignore Playwright MCP artifacts. Verified: mkdocs build --strict clean; libraries fallback renders live. Signed-off-by: disqualifier <dev@disqualifier.me>
99 lines
3.2 KiB
Markdown
99 lines
3.2 KiB
Markdown
# Deployment Guide
|
|
|
|
> Ready for your project to see the light? You may be eligible for deployment on
|
|
> **rethink-net** — our fleet of Ubuntu 26.x servers, ready to host whatever
|
|
> you've built.
|
|
|
|
**Eligible:** APIs, websites, applets, bots, monitors.
|
|
|
|
The whole network runs on a few simple, consistent rules. Get your container to
|
|
follow them and deploying is mostly handing us a `compose.yaml`.
|
|
|
|
## Docker — the services account
|
|
|
|
Every service runs containerized as the shared **`services`** account:
|
|
**uid/gid 1337**, fixed fleet-wide. Build your image to be **uid-agnostic** so it
|
|
runs cleanly as that account:
|
|
|
|
- `user: "1337:1337"` in compose.
|
|
- `chmod -R a+rwX /app` in the Dockerfile (covers non-mounted dirs — see the
|
|
bind-mount note below).
|
|
- `HOME=/tmp`.
|
|
- **No** in-container `user`/`useradd` — don't bake a user into the image.
|
|
|
|
```dockerfile
|
|
FROM python:3.12-slim
|
|
ENV HOME=/tmp
|
|
WORKDIR /app
|
|
# git in the build if you pip-install from git
|
|
RUN apt-get update && apt-get install -y --no-install-recommends git \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
COPY . .
|
|
RUN pip install --no-cache-dir . \
|
|
&& chmod -R a+rwX /app
|
|
CMD ["python", "-m", "yourapp"]
|
|
```
|
|
|
|
```yaml
|
|
services:
|
|
yourapp:
|
|
build: .
|
|
user: "1337:1337"
|
|
environment:
|
|
HOME: /tmp
|
|
volumes:
|
|
- /srv/configs/<project>:/app/config:ro # host-managed, read-only
|
|
- /srv/<dev>/<project>:/app/logs # live + rolled logs
|
|
- yourapp-data:/app/data # named volume — the rest
|
|
|
|
volumes:
|
|
yourapp-data:
|
|
```
|
|
|
|
## Paths and mounts
|
|
|
|
- **Configs** → `/srv/configs/<project>/` — bind mount, host-managed.
|
|
- **Logs** → `/srv/<dev>/<project>/` — bind mount; live and rolled, scraped for
|
|
monitoring.
|
|
- **Everything else** (caches, browser profiles, scratch) → **named volumes**.
|
|
Docker manages ownership, so there are no host permissions to fiddle with.
|
|
|
|
## Permissions — the bind-mount footgun
|
|
|
|
`docker compose up` does **not** create bind-mount directories as you. If a
|
|
bind-mount source is missing, the Docker daemon (**root**) creates it **as
|
|
root** — and your container (**1337**) then can't write it. Logs fall back to
|
|
console-only, caches re-download every run.
|
|
|
|
So:
|
|
|
|
- **Bind-mount sources (configs, logs) must EXIST and be 1337-owned _before_
|
|
`up`.** This is handled at provisioning, not a per-deploy chown hook.
|
|
- **Named volumes avoid this entirely** — use them for anything that doesn't need
|
|
host visibility.
|
|
- The Dockerfile `chmod -R a+rwX /app` only covers **non-mounted** dirs. A bind
|
|
mount overrides the image directory with the host directory, so for mounted
|
|
paths the **host-side ownership wins**.
|
|
|
|
## What your compose / Dockerfile needs
|
|
|
|
- `user: "1337:1337"`
|
|
- bind mounts for **configs + logs**
|
|
- named volumes for **the rest**
|
|
- secrets bind-mounted **`:ro`**
|
|
- `HOME=/tmp`
|
|
- `chmod -R a+rwX /app`
|
|
- `git` in the build if you `pip install` from git
|
|
|
|
## Secrets
|
|
|
|
We do **not** commit secrets (usually, lol). The rule:
|
|
|
|
- Secrets stay **gitignored**.
|
|
- They're placed on the host at `/srv/configs/<project>/`.
|
|
- They're bind-mounted **read-only** at runtime.
|
|
- **Never** baked into the image — add them to `.dockerignore` so `COPY . .`
|
|
can't grab them.
|
|
|
|
Rotating a secret = edit the host file and restart. No rebuild.
|