Initial setup: OpenResto deployment for Lunkaberg breakfast booking
Adapts upstream's release docker-compose.yml to run behind this server's Nginx Proxy Manager on the shared my-main-net network instead of publishing host ports. Includes docs/ for session continuity. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014vNjtg18oTQcv8dtjwnT69
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
# Copy to .env and fill in real values. Never commit the real .env.
|
||||||
|
|
||||||
|
# --- Required ---
|
||||||
|
# JWT signing key, min 32 chars: openssl rand -base64 48
|
||||||
|
JWT_KEY=
|
||||||
|
|
||||||
|
# Public URL this deployment is served on
|
||||||
|
CORS_ORIGINS=https://frukost.lunkaberg.se
|
||||||
|
|
||||||
|
# Seeds the admin account on first boot only
|
||||||
|
ADMIN_EMAIL=
|
||||||
|
ADMIN_PASSWORD=
|
||||||
|
|
||||||
|
# --- Optional: SMTP for booking confirmation emails ---
|
||||||
|
SMTP_HOST=
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USERNAME=
|
||||||
|
SMTP_PASSWORD=
|
||||||
|
SMTP_FROM_EMAIL=
|
||||||
|
SMTP_FROM_NAME=Lunkaberg Frukost
|
||||||
|
SMTP_ENABLE_SSL=true
|
||||||
|
|
||||||
|
# --- Optional: push notifications ---
|
||||||
|
VAPID_PUBLIC_KEY=
|
||||||
|
VAPID_PRIVATE_KEY=
|
||||||
|
VAPID_SUBJECT=
|
||||||
|
|
||||||
|
# --- Optional: Apple/Google Wallet passes ---
|
||||||
|
APPLE_PASS_TYPE_ID=
|
||||||
|
APPLE_TEAM_ID=
|
||||||
|
APPLE_PASS_CERTIFICATE_PATH=
|
||||||
|
APPLE_PASS_CERTIFICATE_PASSWORD=
|
||||||
|
APPLE_WWDR_CERTIFICATE_PATH=
|
||||||
|
GOOGLE_WALLET_ISSUER_ID=
|
||||||
|
GOOGLE_WALLET_SERVICE_ACCOUNT_KEY_PATH=
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.env
|
||||||
|
wallet/
|
||||||
|
well-known/
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
# OpenResto — self-hosted breakfast booking (Lunkaberg)
|
||||||
|
#
|
||||||
|
# Adapted from the official release compose (v2.2.0) to run behind the
|
||||||
|
# existing Nginx Proxy Manager setup on this server: no host ports are
|
||||||
|
# published, all services join the shared `my-main-net` network, and NPM
|
||||||
|
# proxies straight to the `lunkaberg-reverse-proxy` container on port 80.
|
||||||
|
#
|
||||||
|
# Backup: see https://github.com/karanshukla/openresto/blob/main/docs/backup-restore.md
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
media_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
main:
|
||||||
|
external: true
|
||||||
|
name: my-main-net
|
||||||
|
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
image: ghcr.io/karanshukla/openresto-backend:2.2.0
|
||||||
|
container_name: lunkaberg-backend
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- main
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- PORT=8080
|
||||||
|
- CORS_ORIGINS=${CORS_ORIGINS}
|
||||||
|
- JWT_KEY=${JWT_KEY}
|
||||||
|
- ADMIN_EMAIL=${ADMIN_EMAIL}
|
||||||
|
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
||||||
|
- CONNECTION_STRING=Data Source=/data/openresto.db
|
||||||
|
- DATA_PROTECTION_KEYS_PATH=/data/dp-keys
|
||||||
|
- Vapid__PublicKey=${VAPID_PUBLIC_KEY:-}
|
||||||
|
- Vapid__PrivateKey=${VAPID_PRIVATE_KEY:-}
|
||||||
|
- Vapid__Subject=${VAPID_SUBJECT:-}
|
||||||
|
- GuestPush__ReminderLeadHours=${GUEST_PUSH_REMINDER_LEAD_HOURS:-24,2}
|
||||||
|
- GuestPush__ExpoAccessToken=${EXPO_ACCESS_TOKEN:-}
|
||||||
|
- Wallet__Apple__PassTypeIdentifier=${APPLE_PASS_TYPE_ID:-}
|
||||||
|
- Wallet__Apple__TeamIdentifier=${APPLE_TEAM_ID:-}
|
||||||
|
- Wallet__Apple__CertificatePath=${APPLE_PASS_CERTIFICATE_PATH:-}
|
||||||
|
- Wallet__Apple__CertificatePassword=${APPLE_PASS_CERTIFICATE_PASSWORD:-}
|
||||||
|
- Wallet__Apple__WwdrCertificatePath=${APPLE_WWDR_CERTIFICATE_PATH:-}
|
||||||
|
- Wallet__Google__IssuerId=${GOOGLE_WALLET_ISSUER_ID:-}
|
||||||
|
- Wallet__Google__ServiceAccountKeyPath=${GOOGLE_WALLET_SERVICE_ACCOUNT_KEY_PATH:-}
|
||||||
|
- EmailSettings__Host=${SMTP_HOST:-}
|
||||||
|
- EmailSettings__Port=${SMTP_PORT:-587}
|
||||||
|
- EmailSettings__Username=${SMTP_USERNAME:-}
|
||||||
|
- EmailSettings__Password=${SMTP_PASSWORD:-}
|
||||||
|
- EmailSettings__FromEmail=${SMTP_FROM_EMAIL:-}
|
||||||
|
- EmailSettings__FromName=${SMTP_FROM_NAME:-Lunkaberg Frukost}
|
||||||
|
- EmailSettings__EnableSsl=${SMTP_ENABLE_SSL:-true}
|
||||||
|
volumes:
|
||||||
|
- db_data:/data
|
||||||
|
- media_data:/app/wwwroot/media
|
||||||
|
- ./wallet:/wallet:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: ghcr.io/karanshukla/openresto-frontend:2.2.0
|
||||||
|
container_name: lunkaberg-frontend
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- main
|
||||||
|
environment:
|
||||||
|
- EXPO_PUBLIC_API_URL=/api
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8081"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
reverse-proxy:
|
||||||
|
image: ghcr.io/karanshukla/openresto-nginx:2.2.0
|
||||||
|
container_name: lunkaberg-reverse-proxy
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- main
|
||||||
|
# No host port published — Nginx Proxy Manager reaches this container
|
||||||
|
# directly on my-main-net at lunkaberg-reverse-proxy:80.
|
||||||
|
environment:
|
||||||
|
- PORT=80
|
||||||
|
- BACKEND_HOST=backend
|
||||||
|
- BACKEND_PORT=8080
|
||||||
|
- FRONTEND_HOST=frontend
|
||||||
|
- FRONTEND_PORT=8081
|
||||||
|
volumes:
|
||||||
|
- media_data:/usr/share/nginx/html/media:ro
|
||||||
|
- ./well-known:/usr/share/nginx/html/.well-known:ro
|
||||||
|
depends_on:
|
||||||
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
frontend:
|
||||||
|
condition: service_healthy
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Decisions — Lunkaberg Frukost (OpenResto)
|
||||||
|
|
||||||
|
## 2026-09-21 — Use OpenResto rather than build custom
|
||||||
|
Per wanted to evaluate get.openres.to for a client breakfast-booking site.
|
||||||
|
It's MIT-licensed, self-hosted, ASP.NET Core + React + SQLite, ships
|
||||||
|
pre-built multi-arch Docker images and is explicitly designed to sit behind
|
||||||
|
a reverse proxy like NPM. Decided to deploy it as-is rather than build a
|
||||||
|
custom PHP tool, since it already covers table holds, multi-location,
|
||||||
|
service periods, and an admin dashboard out of the box.
|
||||||
|
|
||||||
|
## 2026-09-21 — Git via self-hosted Gitea, not the usual live-edit workflow
|
||||||
|
Per's standing default for hobby projects is no git / live-editing on the
|
||||||
|
server. This is client work, so he's using his Gitea instance
|
||||||
|
(gitea.axbom.com) instead — repo `root/LunkabergB`. `.env` (secrets) is
|
||||||
|
gitignored; `.env.example` documents the required variables.
|
||||||
|
|
||||||
|
## 2026-09-21 — No host ports published for the OpenResto containers
|
||||||
|
Upstream's docker-compose.yml publishes the bundled nginx reverse-proxy
|
||||||
|
container on host port 80 by default, which would collide with this
|
||||||
|
server's Nginx Proxy Manager (already bound to 80/443). Adapted the compose
|
||||||
|
file to join the existing `my-main-net` Docker network instead (same
|
||||||
|
pattern as vox, remark42, etc.) — NPM proxies straight to
|
||||||
|
`lunkaberg-reverse-proxy:80` over the Docker network, no host port needed.
|
||||||
|
|
||||||
|
## 2026-09-21 — Admin email defaulted to per@axbom.se
|
||||||
|
Used as a placeholder so there's a working login immediately; this should
|
||||||
|
be revisited once it's clear who administers bookings day-to-day for the
|
||||||
|
client (Per vs. someone at Lunkaberg).
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# State — Lunkaberg Frukost (OpenResto)
|
||||||
|
|
||||||
|
## What this is
|
||||||
|
Client project for lunkaberg.se — a breakfast booking service, built on
|
||||||
|
[OpenResto](https://get.openres.to) (open source, MIT), self-hosted at
|
||||||
|
`frukost.lunkaberg.se`.
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
- OpenResto v2.2.0, official pre-built images (`ghcr.io/karanshukla/openresto-*`)
|
||||||
|
- Backend: ASP.NET Core 10 + SQLite (in `db_data` volume)
|
||||||
|
- Frontend: React (Expo/React Native web build)
|
||||||
|
- Reverse proxy: bundled nginx container (`lunkaberg-reverse-proxy`), fronted
|
||||||
|
by this server's Nginx Proxy Manager — no host ports published, everything
|
||||||
|
rides the shared `my-main-net` Docker network like the other app projects
|
||||||
|
on this box.
|
||||||
|
- Location: `/var/www/lunkaberg/`
|
||||||
|
- Git: tracked, remote at `https://gitea.axbom.com/root/LunkabergB.git`
|
||||||
|
(this is a client project, so — unlike most of Per's hobby projects —
|
||||||
|
it's using real version control instead of live-editing.)
|
||||||
|
|
||||||
|
## Status as of 2026-09-21
|
||||||
|
- [x] Project directory created, git initialized, Gitea remote added
|
||||||
|
- [x] docker-compose.yml adapted from upstream release for the my-main-net /
|
||||||
|
NPM pattern (no host port conflicts with NPM's own 80/443)
|
||||||
|
- [x] .env created with generated JWT_KEY and admin password (not committed —
|
||||||
|
see .env.example for the template)
|
||||||
|
- [ ] `docker compose up -d` — pulling images / bringing the stack up
|
||||||
|
- [ ] DNS: A record for frukost.lunkaberg.se → 64.112.127.212 (Per manages
|
||||||
|
lunkaberg.se DNS himself)
|
||||||
|
- [ ] NPM proxy host for frukost.lunkaberg.se → lunkaberg-reverse-proxy:80
|
||||||
|
- [ ] First login / admin dashboard walkthrough
|
||||||
|
- [ ] Decide: SMTP for booking confirmation emails (needs a mailbox at
|
||||||
|
lunkaberg.se, separate from Per's personal Migadu setup)
|
||||||
|
- [ ] Decide: push notifications (VAPID), Apple/Google Wallet passes —
|
||||||
|
left disabled for now, app degrades gracefully without them
|
||||||
|
|
||||||
|
## Known issues / watch items
|
||||||
|
- Server disk was at 87% (6.5GB free) before pulling OpenResto images —
|
||||||
|
keep an eye on `df -h` after this and future installs.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# TODO — Lunkaberg Frukost (OpenResto)
|
||||||
|
|
||||||
|
## Next up
|
||||||
|
1. Bring the stack up (`docker compose up -d`) and confirm all three
|
||||||
|
containers report healthy.
|
||||||
|
2. Per: add DNS A record for `frukost.lunkaberg.se` → `64.112.127.212`.
|
||||||
|
3. Create NPM proxy host: `frukost.lunkaberg.se` → `lunkaberg-reverse-proxy:80`,
|
||||||
|
request Let's Encrypt cert, force SSL.
|
||||||
|
4. Log into the admin dashboard with the generated credentials (see .env),
|
||||||
|
change the admin password from the generated one via the UI if it
|
||||||
|
offers that, and set up the restaurant's first location (timezone,
|
||||||
|
hours, tables, floor sections).
|
||||||
|
5. Push the initial commit to Gitea once Per confirms he's ready.
|
||||||
|
|
||||||
|
## Open questions for Per
|
||||||
|
- Who is the actual admin user for the client (Per, or someone at
|
||||||
|
Lunkaberg)? Affects ADMIN_EMAIL and whether Per hands off credentials.
|
||||||
|
- Want booking confirmation emails? Needs SMTP creds — likely a new mailbox
|
||||||
|
at lunkaberg.se via Migadu, separate from Per's personal one.
|
||||||
|
- Any interest in push notifications or Apple/Google Wallet passes, or
|
||||||
|
leave those disabled (current default)?
|
||||||
|
- Branding: restaurant name / primary color / icon are configurable live
|
||||||
|
from the admin dashboard, no redeploy needed — revisit once client has
|
||||||
|
a look.
|
||||||
Reference in New Issue
Block a user