Encrypted push-to-talk voice and group party line over Reticulum.
64
Encrypted push-to-talk voice and group party line over Reticulum. No accounts, no phone numbers, no third-party servers.
| Architecture | Tag |
|---|---|
| x86-64 | amd64 |
Pull and run the interactive menu. Make calls, listen for calls, set secrets, test audio.
Save as docker-compose.yml, then run docker compose run --rm partyline:
services:
partyline:
image: marcusholtz/reticulum-party-line:latest
container_name: reticulum-party-line
stdin_open: true
tty: true
shm_size: "512m"
security_opt:
- label:disable
tmpfs:
- /dev/shm:size=512m,mode=1777
volumes:
- ./data:/app/data
- ./secrets:/run/secrets:ro
- ${XDG_RUNTIME_DIR:-/run/user/1000}/pulse:/run/user/${UID:-1000}/pulse
environment:
- DATA_DIR=/app/data
- RUNTIME_DIR=/dev/shm/partyline
- SHARED_SECRET_FILE=/run/secrets/shared_secret.txt
- REFLECTOR_PORT=4242
- TERM=xterm
- PULSE_SERVER=unix:/run/user/${UID:-1000}/pulse/native
- XDG_RUNTIME_DIR=/run/user/${UID:-1000}
entrypoint: ["docker-entrypoint.sh", "bash", "/app/src/partyline.sh"]
docker run -it --rm \
--name reticulum-party-line \
--security-opt label:disable \
--shm-size 512m \
--tmpfs /dev/shm:size=512m,mode=1777 \
-v ./data:/app/data \
-v ./secrets:/run/secrets:ro \
-v ${XDG_RUNTIME_DIR}/pulse:/run/user/$(id -u)/pulse \
-e DATA_DIR=/app/data \
-e RUNTIME_DIR=/dev/shm/partyline \
-e SHARED_SECRET_FILE=/run/secrets/shared_secret.txt \
-e REFLECTOR_PORT=4242 \
-e TERM=xterm \
-e PULSE_SERVER=unix:/run/user/$(id -u)/pulse/native \
-e XDG_RUNTIME_DIR=/run/user/$(id -u) \
marcusholtz/reticulum-party-line:latest \
docker-entrypoint.sh bash /app/src/partyline.sh
Your RNS identity persists in ./data/ across restarts.
Run a persistent reflector daemon. Callers dial your destination hash and are bridged together.
Using the same docker-compose.yml above, add a reflector profile service, or use the one from the source repo:
# Start reflector in background
docker compose --profile reflector up -d reflector
# Watch live activity
docker compose logs -f reflector
# Stop
docker compose --profile reflector down
docker run -d \
--name reticulum-reflector \
--restart unless-stopped \
--security-opt label:disable \
--shm-size 512m \
--tmpfs /dev/shm:size=512m,mode=1777 \
-v ./data:/app/data \
-v ./secrets:/run/secrets:ro \
-e DATA_DIR=/app/data \
-e RUNTIME_DIR=/dev/shm/partyline \
-e SHARED_SECRET_FILE=/run/secrets/shared_secret.txt \
-e REFLECTOR_PORT=4242 \
marcusholtz/reticulum-party-line:latest \
docker-entrypoint.sh bash /app/src/partyline.sh relay
No audio mounts needed for reflector mode (it forwards encrypted blobs, never decodes audio).
| Parameter | Function |
|---|---|
-e SHARED_SECRET_FILE | Path to secret file inside container. Default: /run/secrets/shared_secret.txt |
-e DATA_DIR=/app/data | Persistent data (identity, config, secret) |
-e RUNTIME_DIR=/dev/shm/partyline | Ephemeral runtime (audio, pids, RNS storage) |
-e REFLECTOR_PORT=4242 | Reflector listen port |
-e RNS_LISTEN_HOST=0.0.0.0 | Reflector bind address |
-e OPUS_BITRATE=16 | Opus encoding bitrate in kbps |
-e CIPHER=aes-256-cbc | Encryption cipher (21 options) |
-e HMAC_AUTH=1 | HMAC-sign protocol messages (0/1) |
-e PULSE_SERVER | PulseAudio/PipeWire socket path |
--shm-size 512m | Required: audio queue and runtime dir live in /dev/shm |
-v /app/data | Identity, secret, config (persistent) |
-v /run/secrets | Shared secret file (read-only mount) |
-v /run/user/$UID/pulse | Host audio socket |
The secret is not an environment variable. It is a bind-mounted file:
mkdir -p secrets
echo -n 'your-shared-secret' > secrets/shared_secret.txt
chmod 600 secrets/shared_secret.txt
Per-run override: docker compose run --rm partyline call <dest> --secret 'my-secret'
A reflector does not need a secret.
The entrypoint starts a headless PulseAudio server inside the container. The host's PulseAudio/PipeWire socket mount is the route to real speakers.
arecord -l # find capture devices on the host
aplay -l # find playback devices on the host
| Property | Detail |
|---|---|
| Encryption | AES-256-CBC + PBKDF2 + HMAC-SHA256 |
| Relay | Zero-knowledge reflector: forwards blobs, never has the secret |
| Authentication | Destination hash + pre-shared secret |
| Forward secrecy | None; rotate secrets between conversations |
| Source | Single bash script + Python RNS bridge, no telemetry |
Three networks, same app, same encryption:
| Project | Transport | Image |
|---|---|---|
| Tor Party Line | Tor hidden services | marcusholtz/tor-party-line |
| I2P Party Line | I2P garlic routing | marcusholtz/i2p-party-line |
| Reticulum Party Line | Reticulum mesh | marcusholtz/reticulum-party-line |
MIT
Content type
Image
Digest
sha256:7bd6fe907…
Size
301.6 MB
Last updated
13 days ago
docker pull marcusholtz/reticulum-party-line