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 pehracp .env.example .env
python3 -c "import secrets; print(secrets.token_hex(32))" # once for SESSION_SECRET, once for DATA_KEYThen 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 psThe 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 -d6. 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 pehraTo upgrade, back up first, then:
git pull
docker compose up -d --buildWithout 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