Cosy self-hosted messenger for family & friends: Android app, web app (PWA) and one Docker container
翻訳待ち
Loading the full README.
Read the full README ↗Everyone has an account (a username and a password, the same on every device); people join a group when a member adds them, or with an invitation code or QR code. Messages, photos, voice notes and drawings stay on your server: no account at a third party, no Google services, no tracking.
.zip, two-person conversations./admin): dashboard, server health, storage, backup & restore, journal with filters, invitation codes, members, groups with a 30-day trash, 2FA, IP allowlist, sign-up open or invitation-only with sign-up links and QR codes that fill the code in, a temporary password for a member who forgot theirs or lost their phone (all their devices signed out, account 2FA removed), new version check (the Android app offers the new APK by itself). The admin never sees group content.You need a machine with Docker and Docker Compose. The image ghcr.io/mrddream/papote is published for linux/amd64 and linux/arm64 (Raspberry Pi 4/5).
Create a folder (for example papote/) with this docker-compose.yml. It reads every setting from .env and includes the optional Whisper container for voice note transcription:
services:
papote:
image: ghcr.io/mrddream/papote:latest
container_name: papote
restart: unless-stopped
ports:
# Host side from .env: BIND_ADDRESS (127.0.0.1 = only a reverse proxy on this machine) and PORT.
- "${BIND_ADDRESS:-127.0.0.1}:${PORT:-3000}:3000"
env_file: .env # every setting comes from .env (see below)
environment:
PORT: 3000 # inside the container, whatever PORT says in .env
BACKUP_DIR: /backups
PAPOTE_PROFILES: ${COMPOSE_PROFILES:-} # lets Papote know Whisper runs next to it
volumes:
- ./data:/data
- ${BACKUP_HOST_DIR:-./backups}:/backups # ideally another disk or a NAS
# Voice note transcription on your machine (optional, ~1-2 GB of RAM):
# COMPOSE_PROFILES=whisper in .env. Its image is only pulled in that case.
whisper:
image: onerahmet/openai-whisper-asr-webservice:v1.9.1
container_name: papote-whisper
profiles: ["whisper"]
restart: unless-stopped
environment:
ASR_MODEL: ${WHISPER_MODEL:-small}
ASR_ENGINE: faster_whisper
volumes:
- ./whisper-cache:/root/.cache
and a .env next to it:
# Admin password (/admin), 12+ characters
ADMIN_PASSWORD=a-long-password-of-your-own
# Host port and address: 127.0.0.1 when the reverse proxy is on this machine, 0.0.0.0 otherwise
PORT=3000
BIND_ADDRESS=127.0.0.1
# Behind a reverse proxy serving HTTPS
TRUST_PROXY=loopback, uniquelocal
SECURE_COOKIES=true
TZ=Europe/Paris
# Optional: GIFs (free key on developers.giphy.com) and voice transcription (empty = off)
GIPHY_API_KEY=
COMPOSE_PROFILES=whisper
# Largest video or document, in MB; new-version check against GitHub
MAX_UPLOAD_MB=20
UPDATE_CHECK=true
If port 3000 is already taken on the machine, change PORT (for example PORT=3080) and point your reverse proxy at it: Papote keeps listening on 3000 inside the container. Every variable is described below.
This is the beginning of the README. Read the rest at the original. Read the full README ↗