🐦 BirdWatchAI Manual Part 8 · Advanced Community Feed
Part 8

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
Don't 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:

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:

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

ItemWhere (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

  1. Set up BirdWatchAI on the new machine following the right install path in Part 3.
  2. Stop monitoring on both machines.
  3. Copy the data folder over (rsync / WinSCP / USB stick).
  4. Start the new machine; verify the dashboard shows the right history, settings, license.
  5. Deactivate the license on the old machine if you're moving rather than cloning β€” most licenses cap at one active install per key.
Don't run both at once Most cameras allow only a handful of simultaneous RTSP streams, and the community backend keys feeders by Device Key β€” running two installs with the same Device Key creates confusing duplicate data on the community side. Pick one machine and stop the other.

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\):

ItemLocation
SettingsData\config.json (passwords encrypted)
Detection databaseData\detections.db (with a JSON backup)
SnapshotsData\Snapshots\ (configurable)
VideosData\Videos\
Uncertain detections…\ForReview\ subfolder
Video summariesData\VideoSummaries\
Music for summariesData\Music\
ID corrections logData\corrections.jsonl
LogsData\Logs\
Licenselicense.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):

ItemLocation (inside data/)
Settingsconfig.json (passwords encrypted)
Detection databasebirdwatch.db (SQLite, WAL)
Snapshotssnapshots/
Video clipsclips/
Logslogs/ (also viewable on the Logs page)
Config backupsconfig.bak/
Data-protection keysdataprotection-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.

Don't port-forward the dashboard to the public internet The dashboard has no login, and the host runs Docker with broad permissions. Tailscale (or WireGuard, or a reverse proxy with authentication) is the right pattern; raw port-forwarding exposes your camera feed and controls to the world.

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.

Nice extras Enable MagicDNS for friendly names instead of numeric IPs, and Tailscale's HTTPS / 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.
FAQ

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.

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.