TubeArchivist uses TA_CACHE_DIR and TA_MEDIA_DIR directly as URL paths.
In Docker these are /cache and /youtube, matching nginx locations.
Our paths (/opt/tubearchivist/cache, /opt/tubearchivist/media) broke
video playback URLs and file downloads.
Create symlinks /cache and /youtube pointing to data dirs, set env vars
to match Docker defaults. Aligns nginx alias paths with official config.
The auth_request subrequest to /api/ping/ through the generic /api
location block doesn't properly forward cookies to the Django backend,
causing 403 for all /cache/ and /media/ requests.
Use a dedicated internal /_auth location that explicitly proxies to
/api/ping/ with Cookie header forwarding.
Beat service starts before manage.py migrate creates the
django_celery_beat tables, causing 'no such table' error.
Add ExecStartPre that waits for migration to complete by
polling the SQLite DB for the crontab table.
ExecStartPre runs Xvfb as a blocking foreground process, preventing
systemd from ever reaching ExecStart (timeout/failure).
Use xvfb-run wrapper to properly manage the virtual display.
Docker copies backend to /app, so APP_DIR=/app maps static/img/ correctly.
Our bare-metal install has backend at /opt/tubearchivist/backend/,
so TA_APP_DIR must point there for fallback thumbnails to resolve.
Fixes missing thumbnails, default-channel-banner.jpg not found error.
Update script migrates existing installs to the corrected path.
Next.js standalone output requires .next/static and public/ to be
copied manually into .next/standalone/ for CSS/JS to be served.
Also source .env before prisma generate in update script.
- Replace Caddy with Nginx (matches upstream Dockerfile)
- Add crypto.randomUUID polyfill in index.html for non-HTTPS access
(browsers only expose crypto.randomUUID in secure contexts)
- Apply polyfill also in update script
- Transmute: replace manual curl with fetch_and_deploy_gh_release prebuild
- Nametag: pass DATABASE_URL to prisma generate (config needs it at load time)
- OTBR: use apt nodejs/npm instead of setup_nodejs (only needed for cmake web build)
- Build from source via git clone + cmake/ninja
- Privileged container for network admin (iptables/ipset/tun)
- Web GUI on port 80, REST API, mDNS service discovery
- Configurable RCP device path in /etc/default/otbr-agent
- Git-based update with shallow fetch + rebuild
Browser uploads fail with ERR_CONNECTION_REFUSED because Museum returns
presigned S3 URLs with localhost:3200 — unreachable from the user's PC.
Changed all three S3 bucket endpoints to use LOCAL_IP:3200.
Museum encrypts emails before storing (encrypted_email column).
Cannot query by plaintext email. Instead select the first user_id
which is the admin user created during first-start setup.
Peer authentication fails when running as root but connecting as
user 'ente'. Use PGPASSWORD with -h 127.0.0.1 to force TCP/password
authentication instead of Unix socket peer auth.
Museum requires an S3-compatible object storage backend for file
uploads. The install script had dummy S3 credentials pointing to
localhost:3200 but no service was running there, causing HTTP 500
on /files/upload-url.
- Install MinIO binary with random password
- Create required buckets (b2-eu-cen, wasabi-eu-central-2-v3, scw-eu-fr-v3)
- Configure museum.yaml with proper S3 credentials and bucket names
- MinIO runs on port 3200 (API) and 3201 (console)
- Add hardcoded OTT (123456) for all emails in museum.yaml so users
don't need to search logs for verification codes
- Replace separate helper scripts with single 'ente-setup' command
that handles: admin whitelisting (user_id from DB), CLI account
add, and subscription upgrade in one guided flow
- Simplify JSON notes to single first-start instruction
The admin CLI requires the user to be whitelisted via their numeric
user_id in museum.yaml's internal.admin field. The helper script
ente-upgrade-subscription now:
1. Looks up user_id from PostgreSQL by email
2. Adds internal.admin to museum.yaml if not present
3. Restarts museum
4. Runs the subscription upgrade
This replaces the previous approach that incorrectly assumed the
first user was auto-admin (that fallback only works when internal
section is completely absent AND was unreliable).
The 'internal.admins' field expects user IDs, not emails. Setting it
to an empty array explicitly disables admin access. Without the field,
museum falls back to treating the first registered user as admin,
which is the correct behavior for self-hosted instances.
- Add 'internal: admins: []' section to museum.yaml so admin CLI
commands work after adding email to the list
- Fix --no-limit flag in helper script (requires 'True' argument)
- Add admin setup step to JSON first-start notes
The server defaults to ./static relative to the working directory.
Without WorkingDirectory in the service, it looks at /static which
doesn't exist, causing 404 on the web UI. Set the absolute path
/opt/oxicloud/static in the .env file.
The labca-gui -init flag does not exit after initialization - it starts
the HTTP server and blocks forever, causing the install to hang.
Removed the -init call; the service handles first-run setup via the
browser /setup route automatically. Also removed system user (runs as
root in LXC).
Ente: Remove circular Caddy :8080 reverse_proxy block that conflicted
with Museum binding to the same port. Museum serves directly on 8080.
Garmin-Grafana: Use GARMINCONNECT_EMAIL and GARMINCONNECT_BASE64_PASSWORD
env vars instead of broken heredoc stdin piping through timeout+uv run.
MFA code piped via stdin only when provided.