# CONTAINER SERVICES (m3-atlas) **Container orchestration with Podman + Traefik reverse proxy** ## OVERVIEW 11 containerized services on dedicated `web` network (10.89.0.0/24) with Traefik SSL termination. ## STRUCTURE ``` containers/ ├── default.nix # Network setup + service imports ├── baserow.nix # 10.89.0.10 - No-code database ├── ghost.nix # 10.89.0.11 - Blog platform ├── kestra.nix # 10.89.0.12 - Workflow orchestration ├── littlelink.nix # 10.89.0.13 - Link aggregator ├── matomo.nix # 10.89.0.14 - Analytics ├── restreamer.nix # 10.89.0.15 - Video streaming ├── slash.nix # 10.89.0.16 - Link shortener └── slash-nemoti.nix # 10.89.0.17 - Personal link shortener ``` ## WHERE TO LOOK | Task | Action | Notes | |------|--------|-------| | Add container | Copy existing .nix, increment IP | Must update default.nix imports | | Fix networking | Check IP conflicts in 10.89.0.0/24 | Gateway always 10.89.0.1 | | Debug Traefik | Check router rules in service file | Domain must match DNS | | Access database | Use `--add-host=mysql:10.89.0.1` | Gateway IP for host services | ## CONVENTIONS ### Container Definition Template ```nix virtualisation.oci-containers.containers. = { image = "registry/image:tag"; ports = ["127.0.0.1::"]; volumes = ["/var/lib/:/data"]; environmentFiles = [config.age.secrets.-env.path]; extraOptions = [ "--network=web" "--ip=10.89.0." "--add-host=mysql:10.89.0.1" # If DB needed ]; }; ``` ### Traefik Integration ```nix services.traefik.dynamicConfigOptions.http = { services..loadBalancer.servers = [{ url = "http://127.0.0.1:"; }]; routers. = { rule = "Host(`.m3ta.dev`)"; service = ""; tls.certResolver = "godaddy"; }; # Legacy redirect (if needed) routers.-old = { rule = "Host(`.m3tam3re.com`)"; service = ""; middlewares = ["redirect-m3ta"]; }; }; ``` ### IP Allocation - **10.89.0.1**: Gateway (host) - **10.89.0.10-17**: Assigned containers - **10.89.0.18+**: Available for new services ## ANTI-PATTERNS - **DON'T** expose ports publicly - bind to 127.0.0.1 only - **DON'T** skip static IP assignment - routing breaks without it - **DON'T** hardcode secrets - use age-encrypted env files - **DON'T** forget to add imports to default.nix ## NOTES - Network created via activation script in default.nix - All services behind Traefik - no direct external access - MySQL/PostgreSQL run on host, accessed via gateway IP - Secrets pattern: `-env.age` with environment variables