Add Unraid deployment setup

docker-compose.unraid.yml bind-mounts data to /mnt/user/appdata/kids-calendar
instead of a named volume, matching Unraid's appdata convention so backup
plugins pick it up. UNRAID.md covers getting the code onto the array,
running via Compose Manager or terminal, reverse-proxy/HTTPS notes, and
updating. Linked from README.
This commit is contained in:
ort
2026-08-15 13:54:28 -04:00
parent 73a1d58838
commit 5c2fde0c86
3 changed files with 159 additions and 0 deletions
+5
View File
@@ -38,6 +38,11 @@ Data lives in a named volume (`kids-calendar-data`), so it survives
container rebuilds. To back it up, back up that volume (or bind-mount
`./data:/app/data` in `docker-compose.yml` instead and back up that folder).
**Running on Unraid specifically?** See [UNRAID.md](UNRAID.md) — it uses
`docker-compose.unraid.yml`, which bind-mounts to
`/mnt/user/appdata/kids-calendar` instead of a named volume, matching
Unraid's usual appdata convention.
### Environment variables
| Variable | Default | Notes |
+138
View File
@@ -0,0 +1,138 @@
# Running on Unraid
This app has no native/compiled dependencies (it uses Node's built-in
`node:sqlite`), so it builds and runs on Unraid's stock Docker exactly like
anywhere else. This file covers the Unraid-specific parts: getting the
code onto the array, where data lives, and how to run it via either the
Compose Manager plugin or the terminal.
## 1. Get the code onto Unraid
Pick whichever is easier for you — both end up with the project folder
somewhere under `/mnt/user/`.
**Option A — copy via network share (no git needed on Unraid):**
Unraid shares `/mnt/user/appdata` over SMB by default. From your Mac:
```bash
mkdir -p /Volumes/appdata/kids-calendar-src # after connecting to \\TOWER\appdata
rsync -av --exclude node_modules --exclude data --exclude .git \
"/Users/ort84/kids calendar/kids-calendar/" /Volumes/appdata/kids-calendar-src/
```
(Connect to the share first via Finder → Go → Connect to Server →
`smb://TOWER/appdata`, adjust the mount path/share name to match your
server.)
**Option B — git clone directly on Unraid:**
Unraid's base OS doesn't ship git. Install the **NerdTools** plugin from
Community Applications, enable `git` in it, then from the Unraid terminal
(Tools → Terminal, or SSH in):
```bash
mkdir -p /mnt/user/appdata/kids-calendar-src
cd /mnt/user/appdata/kids-calendar-src
git clone ssh://git@git.oservr.com:23/ort/KCal.git .
```
This needs the deploy key available on Unraid too (copy `GitOServr/` over
via the same SMB share, then `chmod 600` the private key file — SSH will
refuse a world-readable key just like it did on the Mac). Only do this if
you're comfortable having a copy of that key on the server; Option A avoids
that entirely.
## 2. Create the appdata folder
```bash
mkdir -p /mnt/user/appdata/kids-calendar
```
This is where the SQLite database will live — `docker-compose.unraid.yml`
bind-mounts it in, instead of using a Docker-managed named volume, so it
shows up normally in Unraid's Docker tab and gets picked up by appdata
backup plugins (e.g. CA Backup/Restore) like any other app's data.
## 3. Set up `.env`
In the project folder on Unraid (`kids-calendar-src` from step 1):
```bash
cp .env.example .env
```
Edit `.env` and set:
```
SESSION_SECRET=<a long random value>
```
Generate one with:
```bash
openssl rand -hex 32
```
(Unraid ships `openssl`. If for some reason it's not available, `docker
run --rm node:22-alpine node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"`
works too.)
Leave `COOKIE_SECURE=false` unless you're putting this behind HTTPS (see
"Reverse proxy" below).
## 4. Run it
**Via the Compose Manager plugin (recommended):** install "Docker Compose
Manager" from Community Applications, add a new stack pointing at the
`kids-calendar-src` folder, and have it use `docker-compose.unraid.yml`
(the plugin lets you pick which compose file in the folder to use — if it
only supports a file literally named `docker-compose.yml`, either rename
`docker-compose.unraid.yml` to that inside your Unraid copy, or symlink
it: `ln -s docker-compose.unraid.yml docker-compose.yml`). Start the
stack from the plugin's UI.
**Via terminal:**
```bash
cd /mnt/user/appdata/kids-calendar-src
docker compose -f docker-compose.unraid.yml up -d --build
```
Either way, first boot builds the image (a minute or so), then the
container starts and listens on port 3007.
## 5. Use it
Open `http://<unraid-ip>:3007/signup.html`, create the first parent
account, invite your spouse, add your kids, build out calendars, and grab
each child's kiosk link from the dashboard for their tablet.
## Updating
After pulling/copying new code:
```bash
cd /mnt/user/appdata/kids-calendar-src
docker compose -f docker-compose.unraid.yml up -d --build
```
This rebuilds the image and recreates the container; your data in
`/mnt/user/appdata/kids-calendar` is untouched.
## Reverse proxy / access from outside your LAN
If you're exposing this beyond your home network (e.g. via Swag or Nginx
Proxy Manager, both common on Unraid) with a real HTTPS certificate:
- Point the proxy at `http://<unraid-ip>:3007` internally.
- Set `COOKIE_SECURE=true` in `.env` and re-run the `up -d --build` command
above — otherwise login cookies won't be marked secure and some
browsers/proxies will refuse to send them back over HTTPS.
- Once your household(s) exist, consider setting
`DISABLE_PUBLIC_SIGNUP=true` so `/signup.html` stops accepting new
households.
## Backups
Since data lives at `/mnt/user/appdata/kids-calendar` (a plain file, the
SQLite database), it's covered by whatever you already use to back up
`/mnt/user/appdata` — no special-casing needed.
+16
View File
@@ -0,0 +1,16 @@
services:
kids-calendar:
build: .
container_name: kids-calendar
ports:
- "3007:3007"
volumes:
# Unraid convention: bind-mount to /mnt/user/appdata so it shows up
# in the Docker tab, gets picked up by appdata backup plugins, etc.
# Create this folder before first run (see UNRAID.md).
- /mnt/user/appdata/kids-calendar:/app/data
environment:
- SESSION_SECRET=${SESSION_SECRET:?set a long random value in .env}
- COOKIE_SECURE=${COOKIE_SECURE:-false}
- DISABLE_PUBLIC_SIGNUP=${DISABLE_PUBLIC_SIGNUP:-false}
restart: unless-stopped