4.0 KiB
AdventureLog Setup Summary
What It Is
AdventureLog is a self-hosted travel logging app with a SvelteKit frontend and Django/PostGIS backend. Live at: https://go.jgitta.com
Infrastructure
| Component | Detail |
|---|---|
| Host | siklos (192.168.88.27) |
| Portainer Stack | #47 — adventurelog (endpoint 3) |
| Frontend container | adventurelog-frontend — port 8015 (SvelteKit SSR) |
| Backend container | adventurelog-backend — port 8016 (Django/nginx → gunicorn :8000) |
| Database container | adventurelog-db (PostGIS 16-3.5) |
| Data volumes | /srv/docker/adventurelog/postgres_data/ and /srv/docker/adventurelog/media/ |
| Reverse proxy | Caddy VM (192.168.88.110) — go.jgitta.com block in /etc/caddy/sites/infrastructure.caddy |
Caddy Routing (Critical — Non-Obvious)
AdventureLog has a SvelteKit API proxy that deletes the csrftoken cookie from the browser on every request, making direct browser→Django API calls impossible. The routing is split:
go.jgitta.com {
# GET/HEAD/OPTIONS /api/* → Django directly (port 8016)
# Browser sends session cookie; no CSRF needed for reads.
# Accept: application/json header forces JSON instead of DRF HTML.
@api_read { method GET HEAD OPTIONS; path /api/* }
handle @api_read {
reverse_proxy http://192.168.88.27:8016 {
header_up Accept "application/json"
}
}
# All other requests (pages + POST/PUT/DELETE /api/*) → SvelteKit (port 8015)
# SvelteKit proxy fetches fresh CSRF token server-to-server and handles auth.
@frontend { not path /media* /admin* /static* /accounts* }
handle @frontend { reverse_proxy http://192.168.88.27:8015 }
# Django: media, admin, static, auth endpoints
handle { reverse_proxy http://192.168.88.27:8016 }
}
Why this matters: POST/PUT/DELETE must go through SvelteKit (port 8015 → gunicorn :8000). These requests will NOT appear in the Django nginx access log (/var/log/nginx/access.log inside the backend container). Only GET requests via Caddy appear there.
Portainer Environment Variables
All 17 env vars are stored in Portainer's environment section (not hardcoded in compose). Key ones:
| Variable | Value |
|---|---|
| ORIGIN | https://go.jgitta.com |
| PUBLIC_URL | https://go.jgitta.com |
| CSRF_TRUSTED_ORIGINS | https://go.jgitta.com |
| FRONTEND_URL | https://go.jgitta.com |
| PUBLIC_SERVER_URL | http://server:8000 |
| FRONTEND_PORT | 8015 |
| BACKEND_PORT | 8016 |
| POSTGRES_DB | adventurelog |
| POSTGRES_USER | adventure |
| DEBUG | False |
| DISABLE_REGISTRATION | False |
Secrets (password, secret key, admin credentials) are in Portainer only — not in this file.
Bugs Fixed During Setup
1. CSRF errors on login
Django's CSRF_TRUSTED_ORIGINS must match the public URL exactly. Fixed by setting it in env.
2. GET /api/* returning DRF HTML instead of JSON
Caddy was doing a broken URI rewrite ({1} not expanding). Fixed by removing the rewrite and adding header_up Accept "application/json".
3. Geocode search returning 401
GET requests were going through SvelteKit's proxy, which strips the session cookie on redirect. Fixed by routing GET /api/* directly to Django (see Caddy config above).
4. Category creation returning 500
AdventureLog has an unhandled IntegrityError when a duplicate category slug is created — it returns 500 instead of 400. Workaround: delete duplicate categories via Django shell if this occurs.
5. "Use My Location" button blocked
Caddy's web_secure snippet sets Permissions-Policy: geolocation=(). Changed the go.jgitta.com block to use inline headers with geolocation=(self) instead.
Admin Access
- URL: https://go.jgitta.com/admin
- Username: admin
- Django shell:
docker exec -it adventurelog-backend python manage.py shell
Known Limitations / Not Configured
- No Google Maps API key — geocoding uses OpenStreetMap/Nominatim (works fine)
- No Strava integration
- B2/Kopia backup not configured for this stack