Support Immich URL/API key via docker-compose env vars
Build and push server image / build-and-push (push) Successful in 33s

docker-compose.yml is tracked in a repo meant for publishing, so it can't
hold a real API key. Renamed it to docker-compose.yml.example (placeholder
values, safe to commit) and gitignored the real docker-compose.yml --
deploying is now "cp the example, fill in real values, docker compose up",
no .env file needed.

config.load() now reads IMMICH_URL/IMMICH_API_KEY from the environment
and applies them on top of whatever's in config.json, so setting them in
the compose file's environment: block takes effect without ever touching
the web UI. Env vars always win over the UI-saved values when both are
present -- verified they survive a save() with different UI-entered
values still in place.
This commit is contained in:
2026-07-18 16:05:06 -04:00
parent 2cd7283ce9
commit e7f096ac23
4 changed files with 40 additions and 10 deletions
+3
View File
@@ -11,6 +11,9 @@ server/**/__pycache__/
server/.venv/
server/*.egg-info/
server/data/
# Real deploy config, copied from docker-compose.yml.example -- holds the
# Immich API key, must never be committed.
server/docker-compose.yml
.env
# Editor / OS cruft
+20 -8
View File
@@ -10,13 +10,22 @@ algorithm itself -- it just streams the response straight to the panel.
1. **Get an Immich API key**: in Immich, go to Account Settings -> API Keys
-> New API Key. Read-only access to albums/assets is enough.
2. **Run the server**:
2. **Copy the compose file and fill in your Immich details**:
```
cp docker-compose.yml.example docker-compose.yml
```
Edit `docker-compose.yml` and set `IMMICH_URL`/`IMMICH_API_KEY` under
`environment:`. `docker-compose.yml` is gitignored (it'll hold your real
API key) -- `docker-compose.yml.example` is the one that's committed.
3. **Run the server**:
```
docker compose up -d
```
3. Open `http://<this-machine>:8420/` in a browser, enter your Immich URL
and API key, click **Load Albums**, pick one, and **Save**.
4. On the ESP32's captive portal setup form, set the **Tools Server** field
4. Open `http://<this-machine>:8420/` in a browser, click **Load Albums**,
pick one, and **Save**. (The Immich URL/API key fields will already be
populated from the environment; changing them in the UI has no effect
as long as the env vars are set -- they win on every load.)
5. On the ESP32's captive portal setup form, set the **Tools Server** field
to `<this-machine>:8420`.
## Endpoints
@@ -31,8 +40,10 @@ algorithm itself -- it just streams the response straight to the panel.
## Notes
- Config (including the Immich API key) is stored in `./data/config.json`
on the host via the compose volume mount.
- Album/order/refresh-interval/etc. are stored in `./data/config.json` on
the host via the compose volume mount. Immich URL/API key are too if set
via the web UI, but `IMMICH_URL`/`IMMICH_API_KEY` env vars (see Setup
above) always take precedence when present.
- `/frame/image` isn't authenticated yet. That's fine on a trusted home
LAN for now, but worth revisiting once the ESP32 side is wired up to
send a shared device token.
@@ -47,8 +58,9 @@ Every push to `main` that touches `server/` triggers a Gitea Actions
workflow (`.gitea/workflows/server-docker-build.yml`) that builds this
image and pushes it to this repo's Gitea Container Registry at
`git.thumeit.com/tfaour/espresso-frame-server`. `docker-compose.yml`
already points at that image, so a deploy host doesn't need this repo's
build context at all -- just the compose file:
(copied from `docker-compose.yml.example`, see Setup above) already
points at that image, so a deploy host doesn't need this repo's build
context at all -- just the compose file:
```
docker compose pull
+15 -2
View File
@@ -28,8 +28,21 @@ class FrameConfig(BaseModel):
def load() -> FrameConfig:
with _lock:
if not CONFIG_PATH.exists():
return FrameConfig()
return FrameConfig(**json.loads(CONFIG_PATH.read_text()))
cfg = FrameConfig()
else:
cfg = FrameConfig(**json.loads(CONFIG_PATH.read_text()))
# IMMICH_URL/IMMICH_API_KEY set in the environment (e.g. docker-compose.yml,
# see docker-compose.yml.example) take precedence over whatever's saved
# in CONFIG_PATH, so credentials never need to go through the web UI.
env_url = os.environ.get("IMMICH_URL")
env_key = os.environ.get("IMMICH_API_KEY")
if env_url:
cfg.immich_url = env_url
if env_key:
cfg.immich_api_key = env_key
return cfg
def save(cfg: FrameConfig) -> None:
@@ -8,4 +8,6 @@ services:
- ./data:/data
environment:
- CONFIG_PATH=/data/config.json
- IMMICH_URL=http://your-immich-host:2283
- IMMICH_API_KEY=your-immich-api-key-here
restart: unless-stopped