Elephant – a privacy-first, open-source messaging application made with Go and Flutter. Elephant supports secure authentication, user discovery, and real-time chat over WebSocket, with all communication TLS-protected between client and server.
| Layer | Technology |
|---|---|
| Backend | Go (chi, pgx, gorilla/websocket, golang-jwt, argon2) |
| Mobile | Flutter (http, web_socket_channel, provider, sqflite) |
| Database | PostgreSQL 16 |
| CI/CD | GitHub Actions, Docker Compose, GHCR |
If you just want to run the client application or get a production-ready backend binary without setting up a build environment, head straight over to our GitHub Releases Page.
Here you will find:
- Client Installers: Pre-built application packages (
.apkfor Android ) ready for deployment.
The fastest way to run Elephant is by pulling the published image — no Go toolchain required.
docker run --name elephant-server \
-e PORT=3000 \
-e POSTGRES_HOST=host.docker.internal \
-e POSTGRES_PORT=3000 \
-e POSTGRES_USER=your_db_user \
-e POSTGRES_PASSWORD=your_db_password \
-e POSTGRES_DB=your_db_name \
-e JWT_SECRET=a_secure_32_character_secret_key_phrase \
-p 3000:3000 \
-d commandlinecoding/elephant:latestpodman run --name elephant-server \
-e PORT=3000 \
-e POSTGRES_HOST=host.containers.internal \
-e POSTGRES_PORT=3000 \
-e POSTGRES_USER=your_db_user \
-e POSTGRES_PASSWORD=your_db_password \
-e POSTGRES_DB=your_db_name \
-e JWT_SECRET=a_secure_32_character_secret_key_phrase \
-p 3000:3000 \
-d ghcr.io/commandlinecoding/elephant:latestOnce running, verify the server is healthy:
curl http://HOST:PORT/api/healthYou should see:
{"success":true,"data":{"postgres":"up","timestamp":"..."}}If you're contributing to the backend and want to build from source instead of pulling the published image, use the dev compose override:
# Clone the repo for the compose file and .env template
git clone https://github.com/commandlinecoding/elephant.git
cd elephant
# Copy and fill in environment variables
cp .env.example .env
# Start the stack
docker compose up -d
# or: podman-compose up -dThis builds the server image from server/Dockerfile on every run instead of pulling from GHCR, so your local changes are reflected immediately.
cd server
go mod download
go run main.goMake sure PostgreSQL is running and reachable using the values in your .env file (POSTGRES_HOST, POSTGRES_PORT, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB).
cd server
psql "postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST:$POSTGRES_PORT/$POSTGRES_DB" \
for migration in /app/migrations/*_up.sql; do
filename=$(basename "$migration")
already_applied=$(psql "${DB_URL}" -tAc \
"SELECT COUNT(*) FROM schema_migrations WHERE filename = '${filename}'")
if [ "$already_applied" = "0" ]; then
echo "Applying ${filename}..."
psql "${DB_URL}" -f "$migration"
psql "${DB_URL}" -c \
"INSERT INTO schema_migrations (filename) VALUES ('${filename}')"
echo "${filename} applied."
else
echo "${filename} already applied, skipping."
fi
donecd mobile
flutter pub get
flutter run| Variable | Description | Default |
|---|---|---|
HOST |
Server bind address | 127.0.0.1 |
PORT |
Server port | 3000 |
POSTGRES_USER |
Database username | postgres |
POSTGRES_PASSWORD |
Database password | — |
POSTGRES_DB |
Database name | myapi_db |
POSTGRES_PORT |
Database port | 5432 |
POSTGRES_HOST |
Database host | localhost |
JWT_SECRET |
Secret key for signing JWTs | — |
ARGON_MEMORY |
Argon2id memory cost (KB) | 65536 |
ARGON_ITERATIONS |
Argon2id iteration count | 3 |
ARGON_PARALLELISM |
Argon2id parallelism degree | 2 |
See .env.example for a starting template.
Checkout the API document
Usernames are normalized to lowercase and assigned a random 4-digit discriminator on registration to avoid collisions, e.g. registering as abc may result in the stored username abc.4821. Use the full discriminated username returned in the registration response when logging in.
Run the full backend test suite (unit + integration):
cd server
go vet ./...
go test -v ./...Integration tests under server/tests/ expect a running server and database. Start the stack first, then run:
HOST=$HOST PORT=$PORT go test -v ./tests/...Docker images are built and published to both GHCR and Docker Hub automatically on every version tag push. Android APKs are built and attached to GitHub Releases automatically on every version tag push.
elephant/
├── .github/ # GitHub Actions workflows
├── docs/ # Project documentation
├── mobile/ # Flutter client
│ ├── android/
│ ├── ios/
│ ├── lib/
│ ├── assets/
│ ├── pubspec.yaml
│ └── README.md
├── server/ # Go backend
│ ├── config/ # DB, JWT, Argon2, CORS configuration
│ ├── controllers/ # HTTP handlers
│ ├── env/ # Environment variable loading
│ ├── errors/ # Sentinel error definitions
│ ├── middlewares/ # Auth, CORS, logging, rate limiting
│ ├── migrations/ # SQL migration files
│ ├── models/ # Data models
│ ├── repository/ # Database access layer
│ ├── routes/ # Route definitions
│ ├── services/ # Business logic (auth, users, JWT, WebSocket)
│ ├── tests/ # Integration tests
│ └── Dockerfile
├── compose.yaml # Default: pulls published image
├── compose.dev.yaml # Override: builds server from source
├── .env.example # Environment variable template
└── LICENSE
Checkout CONTRIBUTING.md for more information
See LICENSE for details.
