Advanced Topics
For people who want to go past the defaults: managing the Docker stack from the command line, moving the data folder, running headless, tuning ONVIF motion, backups, and migrating an install between machines.
Docker commands cheat-sheet
The server edition is one container (plus the Watchtower sidecar for one-click updates). These are the operations you'll do most.
Day-to-day
docker logs -f birdwatch # live log tail; Ctrl+C to stop tailing
docker restart birdwatch # bounce the container without recreating
docker stop birdwatch # stop
docker start birdwatch # start
docker compose down # stop both containers
docker compose up -d # start both
docker stats # live CPU / RAM / network per container
docker ps # what's running
Updating
The dashboard's β¬ Update available button is the easy path β it pulls the new image via the Watchtower sidecar and recreates the container in ~90 seconds. The shell equivalent:
cd ~/birdwatch
docker compose pull
docker compose up -d
(On Windows the path is %USERPROFILE%\BirdWatch and a
birdwatch-update.cmd wrapper is included.)
Cleaning up
docker system prune -af # remove all unused images, containers, networks
docker image prune -af # just dangling images
docker rm the birdwatch container blindly
docker compose down followed by docker compose up -d
is the right pattern β it recreates the container with the mounts and
environment from your docker-compose.yml. A raw docker rm
would lose those.
Custom data directory (server)
By default the data folder is ./data next to the
docker-compose.yml file. To put it somewhere else (e.g. on an
external SSD), edit the volumes: line under the birdwatch
service:
volumes:
- /mnt/ssd/birdwatch-data:/data
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
Then copy your existing data over first:
docker compose stop birdwatch
sudo mkdir -p /mnt/ssd/birdwatch-data
sudo rsync -aHv ~/birdwatch/data/ /mnt/ssd/birdwatch-data/
sudo chown -R 1000:1000 /mnt/ssd/birdwatch-data # match the container's user
docker compose up -d
The container won't recreate the database β it'll keep using whatever's in the mounted directory.
Headless / autostart
Server (Linux)
The container has restart: unless-stopped and Docker itself
auto-starts on boot via the systemd service it installs. There's nothing more to
configure β power-cycle the box, log in, run docker ps, and the
container should be back. If it isn't:
sudo systemctl status docker
sudo systemctl enable docker
Server (Windows + Docker Desktop)
Two layers need to come up: Docker Desktop, then the containers. Both are wired
in Part 3 β Windows + Docker.
If you want belt-and-suspenders, the included
setup-scheduled-task.ps1 registers a Scheduled Task that re-runs
birdwatch-start.cmd at user login.
Docker Desktop on Windows requires a logged-in session β for truly hands-off
operation you'll need auto-login on a dedicated account (netplwiz β
uncheck "Users must enterβ¦"). Trade-off: anyone with physical access has that
account's permissions. Acceptable for a homelab box, not a shared PC.
Desktop app
In Settings β Advanced:
- Auto-connect & start on startup β connect to the camera and begin monitoring as soon as the app launches.
- Add BirdWatchAI to Windows startup: the installer's
Start BirdWatch AI when Windows starts option, or
drop a shortcut into the Startup folder
(Win+R β
shell:startup).
ONVIF & motion tuning
Cameras that support ONVIF (most Tapo models, plus many Reolink / Amcrest) can push motion events to the app over the network rather than the app polling for them. Two big wins: less CPU on the host, and zero false triggers from things the camera knows are noise.
To enable: Settings β Camera β Use ONVIF motion detection on. The camera also needs ONVIF turned on in its own app (Tapo: Advanced Settings β Camera Account covers ONVIF too).
ONVIF subscription leases
BirdWatchAI subscribes to PullPoint motion events with a 1-hour lease that's renewed every ~45 minutes. After camera reboots, network churn, or container recreates, stale subscriptions on the camera side can refuse new ones with BadRequest until they expire. Two ways out:
- Wait ~1 hour for the stale lease to time out.
- Reboot the camera (Tapo app β Settings β Restart). Forces a clean subscription state.
Software motion (when ONVIF isn't available)
The app compares recent low-resolution frames and counts changed pixels. The knob is the Motion Threshold (% of pixels that must change). 5% is the default. The desktop's π Telemetry viewer graphs motion % over time so you can see how high real bird visits spike vs. background sway and pick a threshold just below the visits.
Backups & migration
What to back up
| Item | Where (desktop) | Where (server) |
|---|---|---|
| Settings | Data\config.json |
data/config.json |
| Detection database | Data\detections.db + JSON sidecar |
data/birdwatch.db |
| Snapshots | Data\Snapshots\ |
data/snapshots/ |
| Video clips | Data\Videos\ |
data/clips/ |
| License | license.key in program folder |
data/license.key |
| ID corrections log | Data\corrections.jsonl |
data/corrections.jsonl |
The bare minimum for "I want my settings + history back" is the database file plus
config.json. The snapshots and videos are larger and optional.
Snapshot-style backup (server)
From the host, with the container stopped (briefly) so the SQLite file is in a consistent state:
cd ~/birdwatch
docker compose stop birdwatch
tar -czf ~/birdwatch-backup-$(date +%F).tar.gz data/
docker compose start birdwatch
Restore is the inverse: stop the container, untar over the existing
data/, start it.
In-app backup (both editions)
The server's Settings β Backups page can take a snapshot
of config.json on demand and show a diff against any previous
backup. The desktop app has an equivalent "Save settings to file" / "Load
settings from file" pair under the Advanced tab. Neither bundles the database β
use the file-system approach above for full backups.
Migrating to a new machine
- Set up BirdWatchAI on the new machine following the right install path in Part 3.
- Stop monitoring on both machines.
- Copy the data folder over (rsync / WinSCP / USB stick).
- Start the new machine; verify the dashboard shows the right history, settings, license.
- Deactivate the license on the old machine if you're moving rather than cloning β most licenses cap at one active install per key.
File & folder reference
Desktop (Windows)
All data lives in a Data folder beside the program (e.g.
C:\Users\<you>\AppData\Local\BirdWatch AI\Data\):
| Item | Location |
|---|---|
| Settings | Data\config.json (passwords encrypted) |
| Detection database | Data\detections.db (with a JSON
backup) |
| Snapshots | Data\Snapshots\ (configurable) |
| Videos | Data\Videos\ |
| Uncertain detections | β¦\ForReview\ subfolder |
| Video summaries | Data\VideoSummaries\ |
| Music for summaries | Data\Music\ |
| ID corrections log | Data\corrections.jsonl |
| Logs | Data\Logs\ |
| License | license.key (program folder) |
Server (Docker)
All data lives in the data/ folder you mounted into the container
(default ~/birdwatch/data/ on Linux,
%USERPROFILE%\BirdWatch\data\ on Windows):
| Item | Location (inside data/) |
|---|---|
| Settings | config.json (passwords encrypted) |
| Detection database | birdwatch.db (SQLite, WAL) |
| Snapshots | snapshots/ |
| Video clips | clips/ |
| Logs | logs/ (also viewable on the Logs page) |
| Config backups | config.bak/ |
| Data-protection keys | dataprotection-keys/ |
Remote access with Tailscale
The server dashboard is plain HTTP on port 8080, reachable by any
device on your home network. To reach it securely from anywhere β your
phone on cellular, a laptop at the office β the recommended path is a private mesh
VPN. Tailscale is the easiest: it's free for personal use, needs
no port-forwarding, and works even when your ISP puts you behind CGNAT. It builds
an encrypted WireGuard network between your own devices, so the dashboard is
exposed only to you β never the public internet. This works the same
whether your server is a Raspberry Pi, a Linux box, or Windows + Docker.
1. Install Tailscale on the server
Raspberry Pi / Linux:
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
Follow the printed URL to authenticate the machine to your Tailscale account.
Windows (Docker Desktop host): download the installer from
tailscale.com/download, run it, and
sign in from the system-tray icon. Tailscale runs on the Windows host, not
inside the container β since the dashboard is published on the host's port
8080, that's all it needs.
2. Install Tailscale on the devices you'll watch from
Add the Tailscale app to your phone, tablet, or laptop and sign into the same account. Every device you sign in joins one private network and can see the others.
3. Find the server's Tailscale address
On the server, run tailscale ip -4 to print its Tailscale IP (a
100.x.y.z address). If you turn on MagicDNS in the
Tailscale admin console, you can use the machine's name instead of the number.
4. Open the dashboard from anywhere
http://<tailscale-ip>:8080
http://birdwatch.tail-abcd.ts.net:8080 (MagicDNS name)
The dashboard behaves exactly as it does at home β from any network, on any device signed into your tailnet.
tailscale serve if you'd like a
https:// URL. Neither is required β a plain Tailscale IP on port
8080 already gives you private, encrypted access.
Q: Can I watch my feeder from away from home without port-forwarding?
Yes β install Tailscale (above) on the server and on your phone or
laptop, then open the dashboard over the private, encrypted mesh. Don't port-forward
the dashboard to the public internet.
Running multiple feeders
Desktop
Install (or copy the portable build) into separate folders β e.g.
BirdWatchAI-Backyard\ and BirdWatchAI-FrontPorch\ β and
run each. Each folder keeps its own settings, history, and snapshots. Each gets a
different Device Key on the community side, so they show up as separate feeders.
Server
Either run the same compose stack on multiple hosts (one per camera), or β on a
single host β duplicate the birdwatch service in
docker-compose.yml with a different container name, host port, and
data volume:
services:
birdwatch-backyard:
image: ghcr.io/joebarraco/birdwatchai-server:latest
container_name: birdwatch-backyard
restart: unless-stopped
ports: ["8080:8080"]
volumes: ["./data-backyard:/data", "/etc/localtime:/etc/localtime:ro"]
birdwatch-frontporch:
image: ghcr.io/joebarraco/birdwatchai-server:latest
container_name: birdwatch-frontporch
restart: unless-stopped
ports: ["8081:8080"]
volumes: ["./data-frontporch:/data", "/etc/localtime:/etc/localtime:ro"]
Each instance points at a different camera in its own settings, has its own history, and registers as its own feeder on the community side.
Coming soon
A few features have been designed but aren't shipping yet. They're listed here so you know they're on the way β none of them are in the current build.
- Remote config portal β manage settings on multiple feeders from a single web UI without exposing the dashboards individually. Useful for "I have three feeders, two at home and one at my parents'."
- Self-serve software licensing β buy a license and get the key without going through email.
- Tiered community storage subscriptions β for keeping more of your community-shared media for longer.
Track progress on the release notes or the project roadmap.
Credits & support
BirdWatchAI is a product of Bird Brain Solutions LLC. It builds on open technologies including ONNX Runtime (local AI), FFmpeg (video), LibVLC (streaming), OpenStreetMap & Leaflet (maps), Open-Meteo (weather), eBird-derived data (rarity), Wikipedia (species photos), and Supabase (community backend). Thank you for watching the birds with us.
- Product site & downloads: www.birdwatchai.com
- Live community feed: community.html
- Server release repo: github.com/JoeBarraco/birdwatchai-server-releases
- Contact: support@birdwatchai.com