Run from a published image; move source build to docker-compose.build.yaml

docker-compose.yaml now pulls git.goyban.com/goyban/whattodo so it can be used
without the source. publish.sh builds the committed version and pushes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
goyban
2026-10-09 14:58:25 +02:00
parent 39842c72d7
commit 0060cd11bb
6 changed files with 81 additions and 11 deletions
+3
View File
@@ -18,3 +18,6 @@ BIND_ADDR=127.0.0.1
# Behind a reverse proxy, the IPs allowed to set X-Forwarded-For (for login rate limiting).
# FORWARDED_ALLOW_IPS=127.0.0.1
# Development only: build from source instead of pulling the published image.
# COMPOSE_FILE=docker-compose.build.yaml
+1 -1
View File
@@ -10,7 +10,7 @@ COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app ./app
# `docker compose run --rm test`
# `docker compose -f docker-compose.build.yaml run --rm test`
FROM base AS test
COPY requirements-dev.txt .
RUN pip install -r requirements-dev.txt
+30 -8
View File
@@ -16,28 +16,50 @@ A small, self-hosted to-do app for one person. It works in a desktop browser and
Stack: Python (FastAPI) + SQLite with a plain HTML/CSS/JS frontend and no build step. Everything runs in Docker.
## Run locally
## Run
Requirements: Docker with the Compose plugin. Nothing else is installed on the host.
Requirements: Docker with the Compose plugin. You don't need the source code: only `docker-compose.yaml` and a `.env`.
```sh
mkdir whattodo && cd whattodo
# copy docker-compose.yaml and .env.example from this repo into this folder
cp .env.example .env # then edit .env: set APP_PASSWORD and SECRET_KEY
docker compose up -d --build
docker compose up -d
```
Open <http://localhost:8080> and log in with `APP_PASSWORD`.
The database lives in `./data/whattodo.db`, which is git-ignored.
The database lives in `./data/whattodo.db`.
Useful commands:
```sh
docker compose logs -f # follow logs
docker compose down # stop
docker compose up -d --build # rebuild after pulling changes
docker compose pull && docker compose up -d # update to the newest published version
```
To pin a version, set `WHATTODO_TAG=<commit>` in `.env` (default: `latest`).
## Develop (build from source)
`docker-compose.build.yaml` builds the image from this checkout. Add this line to your `.env` so plain `docker compose` uses it:
```sh
COMPOSE_FILE=docker-compose.build.yaml
```
```sh
docker compose up -d --build # build and start
docker compose run --rm test # run the test suite (in Docker)
```
### Publishing the image
`./publish.sh` builds the last commit (uncommitted changes are left out) and pushes it to
`git.goyban.com/goyban/whattodo` as `:latest` and `:<commit>`. `./publish.sh <tag|branch|commit>` publishes another version.
Log in once first with `docker login git.goyban.com`, using a Gitea token with package write access as the password.
### Testing on your phone (same Wi-Fi)
Set `BIND_ADDR=0.0.0.0` in `.env`, run `docker compose up -d`, then open `http://<this-computer's-LAN-IP>:8080` on the phone.
@@ -45,8 +67,8 @@ Browsers only allow "Install app" / "Add to Home Screen" with offline support ov
## Deploy to production
1. On the server, clone the repo and create `.env` from `.env.example`. Use a **new strong** `APP_PASSWORD` and `SECRET_KEY`, and set `COOKIE_SECURE=true`.
2. `docker compose up -d --build`. The app listens on `127.0.0.1:${PORT}`.
1. On the server, put `docker-compose.yaml` in a folder and create `.env` from `.env.example`. Use a **new strong** `APP_PASSWORD` and `SECRET_KEY`, and set `COOKIE_SECURE=true`.
2. `docker compose up -d`. The app listens on `127.0.0.1:${PORT}`.
3. Put it behind a reverse proxy with HTTPS. For example, with Caddy:
```
@@ -83,6 +105,6 @@ Export regularly from Settings, or copy `./data/whattodo.db` while the app is st
app/main.py API: auth, tasks, categories, export/import
app/db.py SQLite schema and setup
app/static/ frontend (index.html, app.js, style.css, PWA files, icons)
tests/ API tests (run with: docker compose run --rm test)
tests/ API tests (run with: docker compose -f docker-compose.build.yaml run --rm test)
tools/make_icons.py regenerates the PNG icons
```
@@ -1,3 +1,5 @@
# Builds the image from source (development). Used instead of docker-compose.yaml when
# COMPOSE_FILE=docker-compose.build.yaml is set in .env, or with -f docker-compose.build.yaml.
services:
whattodo:
build:
+20
View File
@@ -0,0 +1,20 @@
# Runs the published image; no source code needed. Put this file and a .env (from .env.example) in a folder, then:
# docker compose up -d
# Update to the newest published version:
# docker compose pull && docker compose up -d
# To build from source instead, use docker-compose.build.yaml.
services:
whattodo:
image: git.goyban.com/goyban/whattodo:${WHATTODO_TAG:-latest}
restart: unless-stopped
env_file: .env
ports:
# BIND_ADDR=127.0.0.1 -> this computer only; 0.0.0.0 -> also reachable from your phone on the LAN.
- "${BIND_ADDR:-127.0.0.1}:${PORT:-8080}:8000"
volumes:
- ./data:/data
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health')"]
interval: 30s
timeout: 5s
retries: 3
Executable
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Build the app image from a committed version and push it to the Gitea registry.
# Only committed files are used (via `git archive`), so uncommitted work never ends up in the image.
#
# ./publish.sh # builds HEAD
# ./publish.sh v1.2 # builds a tag/branch/commit
#
# One-time setup: docker login git.goyban.com (password = a Gitea token with package write access)
set -euo pipefail
REGISTRY=git.goyban.com
IMAGE="$REGISTRY/goyban/whattodo"
REF="${1:-HEAD}"
cd "$(dirname "$0")"
SHA="$(git rev-parse --short "$REF^{commit}")"
echo "Building $IMAGE from $REF ($SHA)"
git archive --format=tar "$REF" | docker build --target runtime -t "$IMAGE:$SHA" -t "$IMAGE:latest" -
docker push "$IMAGE:$SHA"
docker push "$IMAGE:latest"
echo "Pushed $IMAGE:$SHA and $IMAGE:latest"