Docker installation: start gitrust in 30 minutes with docker-compose¶
Goals¶
At the end of this tutorial, you will know:
- O1. Deploy the minimal gitrust stack (application + PostgreSQL) with docker-compose
- O2. Verify that all three services start correctly and are healthy
- O3. Create the first administrator account and access the web interface
Prerequisites¶
- Technical: a VM or Linux machine (Debian 12 / Ubuntu 22.04 or higher), Docker Engine ≥ 24 installed (
docker --versionresponds), Docker Compose plugin installed (docker compose versionresponds), ports 4000 and 2222 free on the machine - Image Docker gitrust : à construire localement à partir du code source (l'image n'est pas encore publiée sur un registre public). Suivez la section Construire l'image gitrust ci-dessous avant le
docker compose up. - Educational: no prior gitrust tutorial required — this is the starting point of the administrator journey
- Estimated time: ~30 minutes
Construire l'image gitrust¶
Image non encore publiée
gitrust fournit un Dockerfile multi-stage (Rust + Tailwind/DaisyUI) dans le dépôt source, mais aucune image officielle n'est encore publiée sur un registre public (Docker Hub, ghcr.io, quay.io). L'installation Docker officielle est donc expérimentale : il faut cloner le dépôt et construire l'image localement. Le support Docker production sera stabilisé dans une prochaine release.
À la fin, docker image ls | grep gitrust doit afficher l'image locale gitrust:latest. Le build prend ~8-15 min (compilation Rust en release + build CSS Tailwind). Si vous rencontrez une erreur, ouvrez une issue sur le dépôt source — le pipeline Docker n'a pas encore été testé en production.
Overview¶
Before launching any command, let's understand what docker-compose will orchestrate and why.
gitrust is composed of three main services in its minimum configuration. Think of it like three rooms in an apartment calling each other via an internal network:
graph TB
subgraph internet ["Internet / votre navigateur"]
B[Navigateur :4000]
S[Client git/SSH :2222]
end
subgraph docker ["Réseau Docker gitrust_net"]
A["gitrust-app
(Rust, port 4000 + 2222)
Lit la config depuis .env"]
P["postgres
(PostgreSQL 16, port 5432)
Stocke comptes, dépôts, issues"]
R["redis (optionnel)
(Redis 7, port 6379)
Sessions web + cache"]
end
B -->|HTTP| A
S -->|SSH| A
A -->|SQL| P
A -.->|sessions| R
gitrust-app is the core: HTTP server (:4000) + SSH server (:2222) compiled in Rust. It reads its configuration from an .env file and writes bare Git repositories to a Docker volume. PostgreSQL stores all relational data (accounts, organizations, repositories, issues, PRs). Redis is optional in the minimum configuration — it manages web sessions and cache when present.
Dans ce tutoriel, nous utilisons la stack minimale (app + PostgreSQL) suffisante pour évaluer gitrust et démarrer une petite instance. La stack production avec Redis et SMTP se trouve dans template/docker/docker-compose.production.yml.
Step 1: Create the working directory and configuration file¶
Create a directory dedicated to your gitrust instance and position yourself in it:
Create the .env configuration file with the minimum values. Must change the values marked CHANGE_ME:
cat > .env << 'EOF'
# === gitrust — configuration minimale ===
# Changez toutes les valeurs CHANGE_ME avant de démarrer
# Clé secrète de l'application (générez avec : openssl rand -hex 32)
SECRET_KEY=CHANGE_ME_openssl_rand_hex_32
# URL publique de l'instance (sans slash final)
APP_URL=http://localhost:4000
# Base de données PostgreSQL
DATABASE_URL=postgres://gitrust:CHANGE_ME_db_password@postgres:5432/gitrust
POSTGRES_USER=gitrust
POSTGRES_PASSWORD=CHANGE_ME_db_password
POSTGRES_DB=gitrust
# Serveur SSH (port exposé à l'extérieur)
SSH_PORT=2222
# Mode de l'application
RUST_LOG=info
APP_ENV=production
EOF
Now generate a robust secret key and replace the value in .env:
Also choose a password for PostgreSQL and replace both occurrences:
Expected output (verification):
grep SECRET_KEY .env
# → SECRET_KEY=4a7f2c9e1b8d3f6a0e5c2b9d7f4a1e8c3b6d9f2a5e8c1b4d7f0a3e6c9b2d5f8a
Checkpoint: run grep CHANGE_ME .env — the command should return nothing. If it returns rows, these values have not been replaced and the startup will fail.
Step 2: Create the docker-compose.yml file¶
Create the following docker-compose.yml file in /opt/gitrust/. This content corresponds to the gitrust minimum stack — it is reproduced here in full so you can get started without external dependencies:
cat > docker-compose.yml << 'EOF'
# docker-compose.minimal.yml — Stack gitrust minimale (app + PostgreSQL)
# Cas d'usage : évaluation, développement, petite instance (<10 utilisateurs)
# Pour la production : utilisez docker-compose.production.yml (+ Redis + SMTP)
#
# Usage :
# docker compose up -d
# docker compose logs -f gitrust
# docker compose down
version: "3.9"
services:
# ── Base de données ───────────────────────────────────────────────────────
postgres:
image: postgres:16-alpine
container_name: gitrust_postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
# Données persistantes — ne supprimez pas ce volume sans sauvegarde
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- gitrust_net
# ── Application gitrust ───────────────────────────────────────────────────
gitrust:
image: gitrust:latest
container_name: gitrust_app
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
env_file:
# Lit toutes les variables depuis .env — ne commitez jamais ce fichier
- .env
ports:
# Interface web — exposée sur toutes les interfaces de la machine hôte
- "4000:4000"
# Serveur SSH Git — exposé sur le port configuré dans .env
- "${SSH_PORT:-2222}:2222"
volumes:
# Dépôts Git bare — données critiques, sauvegardez ce volume
- git_repos:/var/lib/gitrust/repositories
# Clés SSH du serveur — générées au premier démarrage, persistez-les
- ssh_host_keys:/etc/gitrust/ssh
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- gitrust_net
volumes:
# postgres_data : données relationnelles (comptes, dépôts, issues, PRs)
postgres_data:
# git_repos : dépôts Git bare (le contenu réel des commits)
git_repos:
# ssh_host_keys : clés SSH hôte (fingerprint de votre serveur)
ssh_host_keys:
networks:
gitrust_net:
driver: bridge
EOF
Checkpoint: check that both files are present in /opt/gitrust/:
Expected output:
total 16
drwxr-xr-x 2 root root 4096 avr 17 10:00 .
drwxr-xr-x 8 root root 4096 avr 17 09:55 ..
-rw------- 1 root root 612 avr 17 10:00 .env
-rw-r--r-- 1 root root 2048 avr 17 10:00 docker-compose.yml
Step 3: Start the stack and follow the logs¶
Start all background services:
Expected output:
[+] Running 4/4
✔ Network gitrust_gitrust_net Created 0.1s
✔ Volume "gitrust_postgres_data" Created 0.0s
✔ Container gitrust_postgres Started 0.8s
✔ Container gitrust_app Started 1.2s
Follow the application logs to observe the startup (migrations run automatically):
Expected output (first 15-20 seconds):
gitrust_app | 2026-04-17T10:00:15Z INFO gitrust > Starting gitrust v0.9.0
gitrust_app | 2026-04-17T10:00:15Z INFO gitrust > Connecting to database...
gitrust_app | 2026-04-17T10:00:16Z INFO gitrust > Running database migrations...
gitrust_app | 2026-04-17T10:00:17Z INFO gitrust > Applied 42 migrations successfully
gitrust_app | 2026-04-17T10:00:17Z INFO gitrust > Generating SSH host keys...
gitrust_app | 2026-04-17T10:00:17Z INFO gitrust > SSH host key fingerprint: SHA256:xxxxxxxxxxxxxxxxxxxx
gitrust_app | 2026-04-17T10:00:17Z INFO gitrust > HTTP server listening on 0.0.0.0:4000
gitrust_app | 2026-04-17T10:00:17Z INFO gitrust > SSH server listening on 0.0.0.0:2222
gitrust_app | 2026-04-17T10:00:17Z INFO gitrust > gitrust is ready
Press Ctrl+C to exit log monitoring (containers continue to run).
Checkpoint: check the health status of the services:
Expected output:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
gitrust_app gitrust:latest "/usr/local/bin/gitr…" gitrust 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:4000->4000/tcp, 0.0.0.0:2222->2222/tcp
gitrust_postgres postgres:16-alpine "docker-entrypoint.s…" postgres 2 minutes ago Up 2 minutes (healthy) 5432/tcp
Both containers should display (healthy). If one displays (starting), wait 30 seconds and retry the command. If it shows (unhealthy), check the logs with docker compose logs gitrust or docker compose logs postgres.
Step 4: Create the first administrator account¶
Open your browser and go to http://localhost:4000.
You should see the gitrust homepage with a registration form. As the instance is blank, the first account created automatically becomes administrator.
Remplissez le formulaire :
- Pseudo: your administrator identifier (e.g. admin)
- Email: your email address
- Password: choose a strong password (≥ 12 characters)
Click on Create my account.
Expected output in the logs (visible with docker compose logs -f gitrust):
gitrust_app | 2026-04-17T10:05:00Z INFO gitrust::auth > New user registered: admin (id=1)
gitrust_app | 2026-04-17T10:05:00Z INFO gitrust::admin > First user promoted to administrator: admin
Final checkpoint: log in with your credentials. After logging in, verify that the top right menu shows an Administration link (or navigate to http://localhost:4000/admin). This page is only accessible to administrators — its presence confirms that your account has the admin role.
Your instance URL is http://localhost:4000 and your administrator account is operational.
Summary¶
- ✓ O1 accomplished: the docker-compose stack is deployed —
docker compose psdisplays two(healthy)containers - ✓ O2 accomplished: the three services (app, PostgreSQL, internal network) start correctly — the logs show “gitrust is ready” and the migrations are applied
- ✓ O3 accomplished: the first administrator account is created and the
/adminpage is accessible
And if it doesn't work¶
| Symptôme | Cause probable | Correction |
|---|---|---|
Error: port 4000 is already in use au démarrage |
Un autre service occupe le port 4000 sur la machine hôte | Identifiez le service avec ss -tlnp \| grep 4000 ou lsof -i :4000. Arrêtez-le ou changez le port dans docker-compose.yml : remplacez "4000:4000" par "4001:4000" et accédez sur :4001 |
Le container gitrust_app affiche (unhealthy) ou redémarre en boucle |
La variable DATABASE_URL est incorrecte ou SECRET_KEY contient des caractères spéciaux non échappés |
Vérifiez avec docker compose logs gitrust \| grep ERROR. Assurez-vous que SECRET_KEY est bien une chaîne hexadécimale sans guillemets. Rechargez avec docker compose down && docker compose up -d |
La page http://localhost:4000 affiche « Connection refused » |
Le container n'est pas encore en (healthy) ou le port n'est pas exposé |
Attendez 30 secondes et rechargez. Si le problème persiste, vérifiez que votre pare-feu local (ufw status) autorise le port 4000 |
FATAL: password authentication failed for user "gitrust" dans les logs postgres |
Le mot de passe dans DATABASE_URL ne correspond pas à POSTGRES_PASSWORD |
Supprimez le volume PostgreSQL (docker compose down -v) et relancez — attention : supprime toutes les données |
Next step¶
→ 02 — Systemd installation: native binary + service: discover the installation without Docker for a production deployment with AppArmor hardening (~45 min)
Or if you want to make this instance accessible from the Internet:
→ 04 — Put into production: reverse-proxy TLS, SMTP, automatic backup (~90 min)