screentinker/docker-compose.example.yml
ScreenTinker 4771f62623 ci: release pipeline (tarball, tizen wgt, multi-arch docker) + Docker packaging
- .github/workflows/release.yml: on a v* tag - verify the tag matches VERSION
  (fail-fast guard), run tests, build a source tarball + the unsigned Tizen .wgt
  and publish a GitHub Release with generated notes, and build+push a multi-arch
  (amd64 + arm64) image to ghcr.io/screentinker/screentinker:<version> + :latest.
  The Release (artifacts) and the docker push are independent jobs, so an
  arm64/QEMU docker failure does not block the GitHub Release and is re-runnable.
  Nothing deploys to prod. APK-build-in-CI left as a TODO (keystore secret).
- Dockerfile + .dockerignore: multi-stage node:20-slim image with server +
  frontend + VERSION + scripts; DATA_DIR=/data volume for db/uploads/jwt-secret.
  Verified to build, boot, serve the dashboard + web player, and persist state.
- docker-compose.example.yml: /data volume, SELF_HOSTED, a node-fetch healthcheck
  against /api/status, and an admin-lockout recovery note (reset-admin.js).
- server.js: resolve the OTA APK from DATA_DIR first (a container can mount one
  at /data/ScreenTinker.apk), fall back to the legacy in-repo path, 404 gracefully.
- ci.yml: bump checkout/setup-node to v6 (clears the Node-20 action deprecation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 13:44:51 -05:00

34 lines
1.4 KiB
YAML

# Example docker-compose for self-hosting ScreenTinker.
# cp docker-compose.example.yml docker-compose.yml # then edit to taste
# The container serves plain HTTP on 3001 - front it with a TLS-terminating
# reverse proxy or Cloudflare in production.
services:
screentinker:
image: ghcr.io/screentinker/screentinker:latest
# ...or build from source instead of pulling:
# build: .
restart: unless-stopped
ports:
- "3001:3001"
environment:
SELF_HOSTED: "true" # first registered user becomes admin, no billing
# JWT_SECRET: "set-a-long-random-string" # else one is generated under /data/certs
# DISABLE_HOMEPAGE: "true" # redirect / to the app instead of the landing page
volumes:
- st-data:/data # db, uploads, and the jwt secret persist here
# To enable OTA APK downloads, mount a built APK read-only:
# - ./ScreenTinker.apk:/data/ScreenTinker.apk:ro
healthcheck:
# image is node:20-slim (no curl) - use node's built-in fetch
test: ["CMD", "node", "-e", "fetch('http://localhost:3001/api/status').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s # first boot runs db migrations
# Locked out of the admin account? Reset it with:
# docker exec -it screentinker node scripts/reset-admin.js
volumes:
st-data: