Goal: offer the app to tens, later hundreds, of customers. Each customer gets their own container from the same image; the app itself stays single-tenant.
Target setup
One image, one container per customer, differing only in configuration and data.
One shared PostgreSQL server with one database per customer.
A reverse proxy with automatic TLS (Traefik or Caddy) routing customer subdomains or custom domains to the containers.
Per customer: config file or environment, data volume (see the uploads issue), database, unique session key.
Tasks
Reference docker-compose (or equivalent) with the proxy, PostgreSQL and one example customer.
Provisioning script for a new customer: create database and database user, generate a unique session key and the initial admin password, create config, volume and container, register the domain in the proxy.
Upgrade procedure: roll a new image out customer by customer. Migrations run at start, so it must be possible to stop the rollout when one fails.
Backup and restore per customer (database and data volume).
Health check endpoint for the proxy and for monitoring.
Measure memory use of one idle instance to size the hosts. Not measured yet.
Verify the Docker build with Leptos 0.8; it has not been built since the upgrade.
Depends on
Config file outside the publicly served directory.
Persistent data directory for uploads.
No default admin password.
Configurable database pool size.
Later
Multi-tenancy (one instance serving all customers by domain) would remove the per-container overhead, but needs a tenant identifier in every table and query, in uploads and in e-mails. Revisit when operating hundreds of containers costs more than that rewrite.
Goal: offer the app to tens, later hundreds, of customers. Each customer gets their own container from the same image; the app itself stays single-tenant.
## Target setup
- One image, one container per customer, differing only in configuration and data.
- One shared PostgreSQL server with one database per customer.
- A reverse proxy with automatic TLS (Traefik or Caddy) routing customer subdomains or custom domains to the containers.
- Per customer: config file or environment, data volume (see the uploads issue), database, unique session key.
## Tasks
- Reference `docker-compose` (or equivalent) with the proxy, PostgreSQL and one example customer.
- Provisioning script for a new customer: create database and database user, generate a unique session key and the initial admin password, create config, volume and container, register the domain in the proxy.
- Upgrade procedure: roll a new image out customer by customer. Migrations run at start, so it must be possible to stop the rollout when one fails.
- Backup and restore per customer (database and data volume).
- Health check endpoint for the proxy and for monitoring.
- Measure memory use of one idle instance to size the hosts. Not measured yet.
- Verify the Docker build with Leptos 0.8; it has not been built since the upgrade.
## Depends on
- Config file outside the publicly served directory.
- Persistent data directory for uploads.
- No default admin password.
- Configurable database pool size.
## Later
Multi-tenancy (one instance serving all customers by domain) would remove the per-container overhead, but needs a tenant identifier in every table and query, in uploads and in e-mails. Revisit when operating hundreds of containers costs more than that rewrite.
Two tasks from the list are done, and the four issues this one depends on (#8, #9, #10, #11) are closed.
Docker build verified
Built from Dockerfile after the Leptos 0.8 upgrade, on Docker Desktop 29.8.2 (linux/arm64): build passes in about 5 minutes, image size 243 MB. The page served from the container renders and hydrates in a browser.
Needed two changes first: a .dockerignore (the build context included the 34 GB target directory and the local config.toml, Maildir and data), and an architecture-aware download of cargo-binstall.
Not tried: a build for x86_64.
Checked against a container with an empty PostgreSQL 17 database:
after a few page loads, a login and an upload: 12.3 MiB
PostgreSQL 17 with this one small database, idle: 119 MiB
One instance, nearly empty database, no load — treat it as a lower bound. Even with a generous margin, memory per instance is not what limits hundreds of instances on one host; PostgreSQL and its connection limit are.
Still open
Reference docker-compose with the proxy, PostgreSQL and one example customer
Provisioning script for a new customer
Upgrade procedure
Backup and restore per customer
Health check endpoint
Two tasks from the list are done, and the four issues this one depends on (#8, #9, #10, #11) are closed.
## Docker build verified
Built from `Dockerfile` after the Leptos 0.8 upgrade, on Docker Desktop 29.8.2 (linux/arm64): build passes in about 5 minutes, image size 243 MB. The page served from the container renders and hydrates in a browser.
Needed two changes first: a `.dockerignore` (the build context included the 34 GB `target` directory and the local `config.toml`, `Maildir` and data), and an architecture-aware download of `cargo-binstall`.
Not tried: a build for x86_64.
Checked against a container with an empty PostgreSQL 17 database:
| Check | Result |
|---|---|
| `GET /data/config.toml` (#8) | 404 |
| Config mounted in the old location or in the data directory | container refuses to start |
| Empty database, no admin password (#10) | refuses to start, no account created |
| `admin` as the initial password | rejected as too short |
| Start with `REZERVATOR_ADMIN_PASSWORD` | `admin` created; login with `admin`/`admin` fails, with the given password works |
| Banner uploaded as `../../test banner.PNG` | stored as `test_banner.png` in the data volume, nothing outside it |
| Container replaced, same `/app/data` volume (#9) | banner and its style still served, login still works without the password variable |
| `max_connections = 3` (#11) | the instance held 3 connections |
## Memory use of one instance
- idle: 7.4 MiB
- after a few page loads, a login and an upload: 12.3 MiB
- PostgreSQL 17 with this one small database, idle: 119 MiB
One instance, nearly empty database, no load — treat it as a lower bound. Even with a generous margin, memory per instance is not what limits hundreds of instances on one host; PostgreSQL and its connection limit are.
## Still open
- Reference `docker-compose` with the proxy, PostgreSQL and one example customer
- Provisioning script for a new customer
- Upgrade procedure
- Backup and restore per customer
- Health check endpoint
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Goal: offer the app to tens, later hundreds, of customers. Each customer gets their own container from the same image; the app itself stays single-tenant.
Target setup
Tasks
docker-compose(or equivalent) with the proxy, PostgreSQL and one example customer.Depends on
Later
Multi-tenancy (one instance serving all customers by domain) would remove the per-container overhead, but needs a tenant identifier in every table and query, in uploads and in e-mails. Revisit when operating hundreds of containers costs more than that rewrite.
Two tasks from the list are done, and the four issues this one depends on (#8, #9, #10, #11) are closed.
Docker build verified
Built from
Dockerfileafter the Leptos 0.8 upgrade, on Docker Desktop 29.8.2 (linux/arm64): build passes in about 5 minutes, image size 243 MB. The page served from the container renders and hydrates in a browser.Needed two changes first: a
.dockerignore(the build context included the 34 GBtargetdirectory and the localconfig.toml,Maildirand data), and an architecture-aware download ofcargo-binstall.Not tried: a build for x86_64.
Checked against a container with an empty PostgreSQL 17 database:
GET /data/config.toml(#8)adminas the initial passwordREZERVATOR_ADMIN_PASSWORDadmincreated; login withadmin/adminfails, with the given password works../../test banner.PNGtest_banner.pngin the data volume, nothing outside it/app/datavolume (#9)max_connections = 3(#11)Memory use of one instance
One instance, nearly empty database, no load — treat it as a lower bound. Even with a generous margin, memory per instance is not what limits hundreds of instances on one host; PostgreSQL and its connection limit are.
Still open
docker-composewith the proxy, PostgreSQL and one example customer