Skip to content

Self hosting

Pehra runs on any 64 bit Linux machine with Docker, in the society or in a cloud. One container holds the app, the camera processes and the job worker; everything it keeps is in one data volume.

What you need

  • Docker with Compose, on x86 or ARM.
  • Disk: the image is 4,254 MB with every model (3,088 MB), plus footage for your retention days.
  • Memory and CPU: on our dev box, a 2013 Xeon without AVX2, 8 busy cameras on 6 CPUs used 3,710 MB in all and analysed 2.1 frames a second per camera (the measurement). A watch described by looks costs much more on an old CPU like this one.
  • An https address for phone cameras and Telegram: a Cloudflare tunnel, or your own proxy. On plain http only localhost can use a camera in the browser.

1. Get the code and write .env

git clone https://github.com/inventionsbyhamid/pehra.git
cd pehra
cp .env.example .env
python3 -c "import secrets; print(secrets.token_hex(32))"   # once for SESSION_SECRET, once for DATA_KEY

Then set, in .env:

SESSION_SECRET, DATA_KEY
Two random strings from the command above. Keep DATA_KEY: camera addresses sealed with a lost key cannot be read.
PUBLIC_BASE_URL
The https address people open, used in links and Telegram messages.
OPENROUTER_API_KEY
The AI, for writing watches, checking flagged moments and answering questions. Or set AI_PROVIDER=bedrock with BEDROCK_MODEL and AWS credentials. Without either, a critical moment still alerts, marked unverified.
TELEGRAM_BOT_TOKEN, TELEGRAM_WEBHOOK_SECRET
The token BotFather gives your bot, and one more random string. Telegram needs the https address.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
Optional Google sign in, with https://your.address/auth/google/callback as the redirect. Without them, sign in is by single use links you print on the server.
TRUST_CLOUDFLARE, ALLOW_PRIVATE_STREAMS
true only behind a Cloudflare tunnel; true only when the machine is inside the society's network and pulls cameras on private addresses.

Every other setting is explained in .env.example.

2. Start it

docker compose up -d --build
docker compose ps

The first build downloads every model and checks each by SHA 256. The app listens on port 8000 of this machine only, and is healthy once /healthz answers. The database is migrated on every start.

3. Sign in for the first time

docker compose exec pehra python -m watchful.auth signin-link you@example.com --workspace "Green Park"

Open the printed link: it creates the society and makes you its owner. The Python package is called watchful, after the project Pehra grew out of.

4. Add a camera and connect Telegram

Add cameras as in Getting started. For Telegram, make a bot with BotFather, put its token and a webhook secret in .env, and run docker compose up -d again; the app tells Telegram where to send updates. Then Settings, Telegram, Connect a group, and send the /connect code in your group.

5. Https with a Cloudflare tunnel (optional)

In the Cloudflare dashboard, make a tunnel with a public hostname pointing at http://pehra:8000, save its token as tunnel.token next to compose.yaml, readable only by the tunnel's user, and uncomment the tunnel service in compose.yaml. Set PUBLIC_BASE_URL to that hostname and TRUST_CLOUDFLARE=true.

sudo chown 65532 tunnel.token && sudo chmod 400 tunnel.token
docker compose up -d

6. Backups and upgrades

Everything is in the pehra-data volume: the database, pictures and clips. To copy it:

docker compose stop pehra
docker compose run --rm --no-deps --user root -v "$PWD:/backup" pehra tar czf /backup/pehra-data.tgz -C /app/data .
docker compose start pehra

To upgrade, back up first, then:

git pull
docker compose up -d --build

Without Docker Compose

The development path builds deploy/Dockerfile.dev, runs scripts/fetch_assets.py and uvicorn by hand. It is in the README.

Next: AWS