# 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/:/app/config:ro # host-managed, read-only - /srv//:/app/logs # live + rolled logs - yourapp-data:/app/data # named volume — the rest volumes: yourapp-data: ``` ## Paths and mounts - **Configs** → `/srv/configs//` — bind mount, host-managed. - **Logs** → `/srv///` — 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//`. - 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.