Tandem
Docker app from crywolf203's Repository
Overview
Readme
View on GitHub
Unraid setup guide for Tandem, a self-hosted co-parenting app.
Overview
Tandem keeps what two co-parents share in one place on your own server:
- parenting-time calendar, with swap requests both parents must accept;
- permanent, tamper-evident messages;
- shared expenses with receipts;
- school calendars;
- the child's health cards and documents;
- optional voice calls, recorded only when both parents agree.
It installs on iPhone and Android from the browser like a native app.
ghcr.io/crywolf203/tandem:latest
│
│ One container · one SQLite file in /data
▼
Tandem web app on port 4380
│
│ HTTPS via your reverse proxy (needed to install it on phones)
▼
iPhone / Android home-screen app
The full feature list, every setting and troubleshooting are in the Tandem README. This guide covers the Unraid side.
Install with the template
Apps → search Tandem → Install.
If it isn't listed yet, add this template repository instead: Settings → Docker → Template repositories →
https://github.com/crywolf203/unraid-templates, then Docker → Add Container → Tandem.Check Data (
/mnt/user/appdata/tandemby default).Set Public URL if you'll use Tandem away from home, e.g.
https://tandem.example.com.Apply, then open the WebUI. The first person to open Tandem creates the family and invites the other parent from More → Invite someone.
| Container path | Default host path | Purpose |
|---|---|---|
/data |
/mnt/user/appdata/tandem |
tandem.db (accounts, schedule, messages, expenses, calls) and files/ (documents, card photos, receipts, call recordings). Back this folder up. |
| Container port | Default | Purpose |
|---|---|---|
4380 |
4380 |
Web app and API |
HTTPS and phones
Phones only install Tandem as an app over HTTPS. Point your reverse proxy at the container:
| Proxy | Forward to |
|---|---|
| Nginx Proxy Manager | http://UNRAID-IP:4380 |
| SWAG | http://UNRAID-IP:4380 |
| Cloudflare Tunnel | http://UNRAID-IP:4380 |
Then set Public URL to that address and Behind a reverse proxy (TRUST_PROXY) to true.
Settings in the template
The template shows the everyday settings; the rest are under Show more settings.
| Group | Settings | Notes |
|---|---|---|
| Access | PUBLIC_URL, ALLOW_SIGNUPS, TRUST_PROXY, SECURE_COOKIES, SESSION_DAYS |
Sign-up is invite-only after the first family by default. |
| Files | PUID, PGID, UMASK, TZ |
Keep 99 / 100 on Unraid. |
| School calendars | FEED_REFRESH_HOURS, ALLOW_PRIVATE_FEEDS |
Leave ALLOW_PRIVATE_FEEDS=false unless a calendar file is on your LAN. |
| Weather | WEATHER_PROVIDER, WEATHER_UNITS, ZIP_CENTROIDS_FILE |
auto uses the National Weather Service in the US. |
| Receipt reading | RECEIPT_AI_URL, RECEIPT_AI_MODEL, RECEIPT_AI_KEY |
Optional. Any OpenAI-compatible vision API, including Ollama on your own server. All blank = off. |
| Calls | LIVEKIT_URL, LIVEKIT_API_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, RECORDINGS_DIR |
Optional. Blank LIVEKIT_URL = calls off. See below. |
Every setting is described in the Tandem README.
Optional: calls and local AI
Tandem can run extra services next to the app:
- Calls: LiveKit, Egress for recording, and Redis.
- Local AI: Ollama for reading receipts, and Whisper for future call transcripts.
These need several containers wired together, so they install with Docker Compose rather than this single template. On Unraid, use the terminal or the Compose Manager plugin.
mkdir -p /mnt/user/appdata/tandem && cd /mnt/user/appdata/tandem
curl -fsSLO https://raw.githubusercontent.com/crywolf203/tandem/main/docker-compose.yml
curl -fsSLO https://raw.githubusercontent.com/crywolf203/tandem/main/setup.sh && chmod +x setup.sh
./setup.sh
setup.sh asks which add-ons to turn on, then:
- creates the call server's key and secret;
- picks GPU or CPU (install the Nvidia Driver plugin first if you have a GPU);
- writes
.env.
Then docker compose up -d starts Tandem and the add-ons together.
Add-on data goes in /mnt/user/appdata/tandem-addons. Use Compose or this template for Tandem, not both, so there's only one Tandem container on the data folder.
Calls also need two things outside Unraid; setup.sh prints the exact values:
- Reverse proxy: a host name such as
calls.example.com→http://UNRAID-IP:7880, with WebSockets on. A Cloudflare Tunnel works for this part. - Router port forwards, straight to Unraid (not through a tunnel): UDP
50000–50100for call audio, and TCP7881as a fallback.
If your internet provider uses CGNAT (no public IP of your own), port forwarding can't work. Run the calls add-on on a small VPS instead.
Recording happens only when both parents turn it on in More → Calls, and both phones show it during the call.
Updating
On the latest tag, Tandem updates through Unraid's normal Check for Updates. Database changes apply automatically on start.
An image update does not add new fields to a template you already saved. When a release adds a setting, it's listed in the release notes. Add it by editing the container, or remove and re-add the container from Apps → Previous Apps to pick up the new template.
Backups
Everything is in the Data folder. Include /mnt/user/appdata/tandem in the Appdata Backup plugin schedule. It stops the container, copies the folder and restarts.
Support
- Template problems: unraid-templates issues
- App problems and feature requests: Tandem issues
Tandem's reports are factual exports of what's stored. Tandem is not legal advice.
Requirements
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/crywolf203/tandem:latestRuntime arguments
- Web UI
http://[IP]:[PORT:4380]/- Network
bridge- Shell
sh- Privileged
- false
- Extra Params
--restart unless-stopped
Template configuration
Port for the web app. Change the host side only if 4380 is already used.
- Target
- 4380
- Default
- 4380
- Value
- 4380
Holds tandem.db (all accounts, schedules, messages, expenses) and files/ (uploaded documents and card photos). Back this folder up.
- Target
- /data
- Default
- /mnt/user/appdata/tandem
- Value
- /mnt/user/appdata/tandem
The address people use to reach Tandem, e.g. https://tandem.example.com. Used to build invite links. When it starts with https://, secure cookies turn on automatically. Leave blank for LAN-only use.
- Target
- PUBLIC_URL
Default time zone for new families and server logs (IANA name). Each family can change its own time zone in the app.
- Target
- TZ
- Default
- America/New_York
- Value
- America/New_York
false (recommended): the first person to open Tandem creates the first family; everyone after that needs an invite link. true: anyone who can reach the server can create their own family.
- Target
- ALLOW_SIGNUPS
- Default
- false
- Value
- false
User ID that owns files in Data. Unraid default is 99 (nobody).
- Default
- 99
- Value
- 99
Group ID that owns files in Data. Unraid default is 100 (users).
- Default
- 100
- Value
- 100
File permission mask for new files in Data. 022 lets only the owner write; 002 also lets the group write.
- Default
- 022
- Value
- 022
Set to true when Tandem sits behind a reverse proxy, so sign-in rate limiting uses the real visitor IP from X-Forwarded-For.
- Target
- TRUST_PROXY
- Default
- false
- Value
- false
Blank = automatic (on when PUBLIC_URL is https). Force with true or false.
- Target
- SECURE_COOKIES
How long a device stays signed in.
- Target
- SESSION_DAYS
- Default
- 60
- Value
- 60
Name shown on the sign-in screen and in reports.
- Target
- APP_NAME
- Default
- Tandem
- Value
- Tandem
true writes one line per request to the container log. Useful for troubleshooting.
- Target
- LOG_REQUESTS
- Default
- false
- Value
- false
How often linked school and district calendars are downloaded again. 0 turns background refresh off; parents can still refresh a calendar from the app.
- Target
- FEED_REFRESH_HOURS
- Default
- 6
- Value
- 6
false (recommended) refuses school calendar links that point at private addresses like 192.168.x.x or localhost, so a link can't be used to probe your network. Set true only if you host a calendar file on your own LAN.
- Target
- ALLOW_PRIVATE_FEEDS
- Default
- false
- Value
- false
auto: US National Weather Service for US locations, Open-Meteo elsewhere. nws: US only, free, includes severe-weather alerts. openmeteo: worldwide, free for non-commercial use. off: no weather.
- Target
- WEATHER_PROVIDER
- Default
- auto|nws|openmeteo|off
- Value
- auto
Temperatures in fahrenheit or celsius.
- Target
- WEATHER_UNITS
- Default
- fahrenheit|celsius
- Value
- fahrenheit
Optional file that turns ZIP codes into locations on your server instead of using Open-Meteo's geocoding. Accepts the Census ZCTA gazetteer file or a zip,lat,lon CSV in your appdata folder.
- Target
- ZIP_CENTROIDS_FILE
- Default
- /data/zip-centroids.csv
- Value
- /data/zip-centroids.csv
OpenAI-compatible API with a vision model, e.g. https://api.openai.com/v1 or a local Ollama server like http://192.168.1.10:11434/v1. Leave blank to turn receipt reading off; receipts can still be attached.
- Target
- RECEIPT_AI_URL
Vision model name, e.g. gpt-4o-mini, or a local model like qwen2.5vl or llama3.2-vision.
- Target
- RECEIPT_AI_MODEL
API key for the receipt reader, if it needs one. Local servers usually don't.
- Target
- RECEIPT_AI_KEY
Voice calls between parents use a LiveKit server. Address phones use to reach it, e.g. wss://calls.example.com. Blank turns calls off. The easiest way to run LiveKit and recording is the calls add-on: install Tandem with Docker Compose and run ./setup.sh (see the README).
- Target
- LIVEKIT_URL
Where Tandem reaches the LiveKit server API, e.g. http://192.168.1.10:7880. Blank = the same host as the call server address.
- Target
- LIVEKIT_API_URL
LiveKit API key.
- Target
- LIVEKIT_API_KEY
LiveKit API secret (at least 32 characters). Keep it private.
- Target
- LIVEKIT_API_SECRET
Folder inside the container where LiveKit Egress leaves finished recordings. Tandem copies each one into Data with a fingerprint, then removes it. Map a host folder here only if you run Egress yourself.
- Target
- RECORDINGS_DIR
- Default
- /recordings
- Value
- /recordings