Docker
Run tripplan.ing with Docker using the Node adapter, SQLite, and filesystem storage. This is suitable for self-hosted deployments, testing, or environments without Cloudflare access.
Prerequisites
- Docker installed
- Stripe and Mailgun credentials (for payment and email features)
Building the image
docker build -t tripplan-ing .The Dockerfile uses the Node adapter instead of the Cloudflare adapter, producing a standard Node.js server.
Running the container
docker run --rm -p 3000:3000 \
-e STRIPE_SECRET_KEY=sk_test_... \
-e STRIPE_WEBHOOK_SECRET=whsec_... \
-e MAILGUN_API_KEY=key-... \
-e MAILGUN_DOMAIN=mg.example.com \
-e PLATFORM_OPERATOR_EMAILS=admin@example.com \
-e PLATFORM_DOMAIN_SUFFIX=localhost \
-v $(pwd)/data:/app/data \
tripplan-ingThe app starts at http://localhost:3000.
Data persistence
The Node runtime stores data in /app/data inside the container:
| Path | Purpose |
|---|---|
/app/data/local.db | SQLite database |
/app/data/objects/ | Photo and document files |
Mount a volume (-v) to persist data across container restarts. Without a volume, data is lost when the container stops.
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
STRIPE_SECRET_KEY | For payments | — | Stripe API key |
STRIPE_WEBHOOK_SECRET | For payments | — | Stripe webhook secret |
MAILGUN_API_KEY | For email | — | Mailgun API key |
MAILGUN_DOMAIN | For email | — | Mailgun domain |
PLATFORM_OPERATOR_EMAILS | Yes | — | Comma-separated operator emails |
PLATFORM_DOMAIN_SUFFIX | Yes | — | Domain suffix for events |
DATABASE_URL | No | file:/app/data/local.db | SQLite database path |
FILES_DIR | No | /app/data/objects | File storage directory |
ENABLE_DEV_BYPASS | No | false | Skip auth (development only) |
Node runtime differences
The Docker deployment uses the same Node runtime as local development:
| Feature | Cloudflare | Docker/Node |
|---|---|---|
| Database | D1 (edge SQLite) | better-sqlite3 (local file) |
| Sessions | KV (persistent, global) | In-memory Map (lost on restart) |
| File storage | R2 (S3-compatible) | Filesystem |
| Auto-migration | No (CI runs migrations) | Yes (on startup) |
| Demo seed data | No | Yes (first run) |
Session persistence
The in-memory KV store means sessions are lost on container restart. Users will need to re-authenticate after a restart. For production Docker deployments, consider implementing a persistent KV adapter (e.g., Redis-backed) or accept the restart trade-off.
Auto-migration
The Node runtime automatically applies pending migrations on startup. No need to run a separate migration step before starting the container.
Multi-event routing
For Docker deployments with multiple events, set up hostname routing:
- Create events in the platform UI at
/platform/events/create - Configure domains in
platform_event_domains - Set up a reverse proxy (Nginx, Caddy, Traefik) to route subdomains to the container
- Ensure DNS points subdomains to the proxy
For a single-event deployment, the app automatically falls back to the first event when hostname resolution fails.
Health checks
The app responds to standard HTTP requests. Use the homepage as a health check endpoint:
curl http://localhost:3000/Related pages
- Deployment Overview — compare Cloudflare vs Docker
- Environment & Secrets — full environment variable reference
- Creating Events — set up events after deployment
- Local Development — same runtime, development workflow