Run the Phone Agent relay on your own machine. Your phone connects to your server, your apps send messages to your server, and nothing leaves your network. This page shows you exactly how to download it, run it, and send your first message — in about three commands.
Private Server is a paid add-on. After you sign in with a paid account that includes Private Server, download the saved Docker image from your account page. One file works on Linux, macOS, and Windows with Docker Desktop.
phoneagent-private-server-v0.1.1.tar
docker save
After download, put the .tar file in a folder where you can run terminal commands.
# Linux / macOS
sha256sum phoneagent-private-server-v0.1.1.tar
# Windows PowerShell
Get-FileHash .\phoneagent-private-server-v0.1.1.tar -Algorithm SHA256
docker load -i phoneagent-private-server-v0.1.1.tar
pip install, nothing to compile on your machine.
The Private Server validates against the central license server on startup. Sign in to your
account page and click Generate server credentials
under Private Server. You will get a .env-style block to paste into the
container's environment:
PHONE_AGENT_LICENSE_SERVER_URL=https://phonerelay.dev
PHONE_AGENT_API_KEY=...
PHONE_AGENT_ACTIVATION_TOKEN=...
PHONE_AGENT_LICENSE_BEARER=...
PHONE_AGENT_LICENSE_BEARER_EXPIRES_AT=...
One docker run — the container listens on 0.0.0.0:8443 inside, mapped to your
host port. Save the license env block from step 2 as phoneagent.env first, then:
docker run -d \
--name phoneagent-server \
-p 8443:8443 \
-v phoneagent-data:/data \
--env-file phoneagent.env \
-e AUTH_SECRET_KEY="replace-with-random-secret" \
-e MIDDLE_ADMIN_TOKEN="replace-with-random-admin-token" \
-e GTS_DEVICE_PEPPER_RING="v1:replace-with-private-pepper-32chars-min" \
phonerelay/private-server:v0.1.1
Or with docker-compose:
# docker-compose.yml
services:
phoneagent:
image: phonerelay/private-server:v0.1.1
container_name: phoneagent-server
restart: unless-stopped
ports:
- "8443:8443"
volumes:
- phoneagent-data:/data
env_file:
- phoneagent.env # contains PHONE_AGENT_LICENSE_* from your account page
environment:
- PHONEAGENT_PUBLIC_HOST=your-ip-or-domain
- AUTH_SECRET_KEY=replace-with-random-secret
- MIDDLE_ADMIN_TOKEN=replace-with-random-admin-token
- GTS_DEVICE_PEPPER_RING=v1:replace-with-private-pepper-32chars-min
volumes:
phoneagent-data:
private-server license: ...: the container is
refusing to boot because the license check failed (missing env vars, expired bearer, cancelled
subscription). Re-generate credentials from your account page, update the env, and restart.
On first run, get the API key + pairing QR from the container logs:
docker logs phoneagent-server
Phone Agent Server v1.0.0
Listening on https://0.0.0.0:8443
API key: pa_live_8f3c… ← use this as Bearer token
Phone QR: open https://<your-ip>:8443/qr in the Android app
https://<your-ip>:8443/qr in a browser and scan it with the Phone Agent Android app to
pair the phone with this server.
If you prefer short commands, download the helper file next to the Docker tar and load it into your shell:
source ./phoneagent-private-server-aliases.sh
pa-init-env
pa-load phoneagent-private-server-v0.1.1.tar
pa-start
pa-health
pa-webchat
To keep the commands available in every new terminal:
echo 'source ~/Downloads/phoneagent-private-server-aliases.sh' >> ~/.bashrc
source ~/.bashrc
Useful commands after it is loaded:
pa-init-env — create .phoneagent-private.env with strong random secrets.pa-load <tar> — load the downloaded Docker image.pa-start / pa-stop / pa-restart — manage the container.pa-health — check /health.pa-logs — follow container logs.pa-webchat — open the local WebChat URL..phoneagent-private.env. Keep that file private and do not commit it.
Once the phone is paired, send a message via the HTTP API:
curl -X POST https://<your-ip>:8443/api/v1/messages \
-H "Authorization: Bearer pa_live_8f3c…" \
-H "Content-Type: application/json" \
-d '{
"channel": "sms",
"to": "+15551234567",
"text": "Hello from my private server!"
}'
import requests
requests.post(
"https://your-ip:8443/api/v1/messages",
headers={"Authorization": "Bearer pa_live_8f3c…"},
json={"channel": "sms", "to": "+15551234567", "text": "Hello!"},
verify=False, # set to your cert path in prod
)
Full request/response reference: HTTPS API.
Configure via environment variables on the docker run (or environment: in
docker-compose). The common knobs:
Generate production secrets before first boot:
python3 -c "import secrets; print(secrets.token_urlsafe(48))"
docker run -d --name phoneagent-server \
-p 8443:8443 \
-v phoneagent-data:/data \
-e AUTH_SECRET_KEY="replace-with-random-secret" \
-e MIDDLE_ADMIN_TOKEN="replace-with-random-admin-token" \
-e GTS_DEVICE_PEPPER_RING="v1:replace-with-private-pepper-32chars-min" \
-e PHONEAGENT_API_KEYS=pa_live_8f3c,pa_live_other \
-e PHONEAGENT_IP_ALLOWLIST=10.0.0.0/8 \
-e PHONEAGENT_RATE_PER_MINUTE=60 \
-e PHONEAGENT_QUEUE_MAX=1000 \
-e PHONEAGENT_TLS_CERT=/data/cert.pem \
-e PHONEAGENT_TLS_KEY=/data/key.pem \
phonerelay/private-server:v0.1.1
All variables:
AUTH_SECRET_KEY — required. Strong random secret for account/session signing.MIDDLE_ADMIN_TOKEN — required. Strong admin token, 20+ characters.GTS_DEVICE_PEPPER_RING — required. Private server-side pepper ring, for example v1:<32+ random chars>.PHONEAGENT_API_KEYS — comma-separated bearer tokens (auto-generated on first boot if unset)PHONEAGENT_IP_ALLOWLIST — CIDR list, comma-separated. Empty = allow all.PHONEAGENT_RATE_PER_MINUTE — per-key rate limit. Default 60.PHONEAGENT_QUEUE_MAX — max messages buffered if phone is offline. Default 1000.PHONEAGENT_TLS_CERT / PHONEAGENT_TLS_KEY — optional. Self-signed cert is generated on first boot if unset.PHONEAGENT_PUBLIC_HOST — your-ip-or-domain, used in the pairing QR code.State (DB, generated certs, queued messages) lives in the /data volume inside the container.
Mount it to a persistent volume (-v phoneagent-data:/data) so restarts don't wipe pairings.
Recommended for production deployments:
PHONEAGENT_TLS_CERT/_KEY, or run behind a reverse proxy (nginx, Caddy, Traefik) that terminates TLS and proxies plaintext to :8443 inside.-p 127.0.0.1:8443:8443) or rely on Docker network isolation + a reverse proxy for public exposure.PHONEAGENT_API_KEYS in Docker secrets / systemd EnvironmentFile; rotate on staff changes.PHONEAGENT_RATE_PER_MINUTE — protects the phone from runaway senders./data to a named volume; queued messages, pairings, and certs live there.GET /health for Docker healthcheck, GET /metrics for Prometheus..tar, run docker load -i phoneagent-private-server-vX.Y.Z.tar, update your compose image tag, then docker compose up -d.Day-to-day API usage: HTTP API Examples. Web UI for sending: WebChat.