ENV Sync — Dokumentation
Self-hosted Secret- und Umgebungsvariablen-Management für Teams. Vergleichbar mit Doppler oder Infisical — vollständig unter eigener Kontrolle.
1. Was ist ENV Sync?
ENV Sync ist ein selbst gehostetes Tool zur zentralen Verwaltung von Umgebungsvariablen und Secrets für Entwicklungsteams. Statt .env-Dateien per Slack oder Git-Repository zu teilen, werden alle Variablen verschlüsselt in einer zentralen Datenbank gespeichert und über CLI oder Dashboard zugänglich gemacht.
Kernfunktionen
- AES-256-GCM-Verschlüsselung aller Secrets
- Projekte mit mehreren Environments (Development, Staging, Production…)
- Team-Berechtigungen pro Projekt (Viewer / Editor / Admin)
- Vollständige Versionshistorie — jeder Push ist unveränderlich gespeichert
- Rollback auf beliebige frühere Version
- Environment-Vergleich und Diff-Ansicht
- Variablensuche über alle Environments
- Webhooks bei Änderungen
- IP-Allowlisting pro Projekt
- Audit-Log aller Aktionen
- Zwei-Faktor-Authentifizierung (TOTP)
2. Architektur
Drei Komponenten
| Komponente | Technologie | Beschreibung |
|---|---|---|
envsync-api | Python 3.12, stdlib-only + cryptography | REST-API, SQLite, eigenes HTTP-Framework |
envsync-dashboard | Vanilla JS, Single-HTML-File | SPA ohne Framework, wird von Nginx ausgeliefert |
envsync-cli | TypeScript / Node.js, zero external deps | Kommandozeilen-Client |
Datenbankschema (SQLite)
3. Installation & Erststart
Voraussetzungen
- Docker + Docker Compose
- Python 3.9+ (nur lokal ohne Docker)
- Port 3002 (API) und 28080 (Dashboard) frei
Erststart mit Docker
# 1. Repository klonen
git clone <repo-url>
cd envsync-deploy
# 2. Konfiguration generieren
make setup
# → erstellt .env mit zufälligem Master Key
# → .env editieren: ENVSYNC_DEMO_EMAIL setzen
# 3. Services starten
make up
# 4. Zugangsdaten anzeigen
make logs-api | grep -A5 "Demo user"
Services: Dashboard http://localhost:28080 · API http://localhost:3002
Erstanmeldung
Beim ersten Start wird ein Demo-User angelegt. Die Zugangsdaten erscheinen in den API-Logs:
make logs-api
──────────────────────────────────────────────────────
✓ Demo user created
Email: admin@yourdomain.com
API key: esk_xxxxxxxxxxxxxxxxxxxxxx
Test it:
curl -H 'Authorization: Bearer esk_xxx' http://localhost:3002/v1/auth/me
──────────────────────────────────────────────────────
Der erste registrierte User erhält automatisch Superuser-Rechte. Die Registrierung kann im Admin-Panel deaktiviert werden (nur Einladungslinks dann möglich).
4. Konfiguration
Alle Einstellungen werden über Umgebungsvariablen in .env gesetzt.
Pflichtfelder
| Variable | Beschreibung |
|---|---|
ENVSYNC_MASTER_KEY | AES-256-GCM-Schlüssel (32 Bytes, Base64). In Produktion zwingend erforderlich. |
# Schlüssel generieren
python3 -c "import os,base64; print(base64.b64encode(os.urandom(32)).decode())"
# oder:
make key
Optionale Felder
| Variable | Standard | Beschreibung |
|---|---|---|
ENVSYNC_DEMO_EMAIL | demo@envsync.dev | E-Mail des Seed-Admins |
ENVSYNC_DEMO_KEY | zufällig | Fester API-Key für Seed-Admin |
ENVSYNC_DB | envsync.db | Pfad zur SQLite-Datenbankdatei |
ENVSYNC_REGISTRATION_DISABLED | false | Offene Registrierung deaktivieren |
ENVSYNC_APP_URL | http://localhost:28080 | Öffentliche Dashboard-URL (für E-Mail-Links) |
PORT | 3001 | API-Listening-Port |
HOST | 0.0.0.0 | API-Listening-Host |
ENVSYNC_RATE_LIMIT | 600 | Max. Requests pro Zeitfenster pro IP |
ENVSYNC_RATE_WINDOW | 60 | Zeitfenster in Sekunden |
E-Mail (SMTP)
| Variable | Beschreibung |
|---|---|
SMTP_HOST | SMTP-Server (z.B. smtp.postmarkapp.com) |
SMTP_PORT | Port (Standard: 587) |
SMTP_USER | SMTP-Benutzername |
SMTP_PASSWORD | SMTP-Passwort |
SMTP_FROM | Absender-Adresse |
Stripe (optional)
| Variable | Beschreibung |
|---|---|
STRIPE_SECRET_KEY | Stripe Secret Key |
STRIPE_WEBHOOK_SECRET | Stripe Webhook Signing Secret |
STRIPE_TEAM_PRICE_ID | Stripe Price ID für Team-Plan |
STRIPE_ENT_PRICE_ID | Stripe Price ID für Enterprise-Plan |
CLI-Umgebungsvariablen
| Variable | Beschreibung |
|---|---|
ENVSYNC_API_KEY | API-Key override (für CI/CD ohne interaktiven Login) |
ENVSYNC_API_URL | API-URL override (überschreibt .envsync-Konfiguration) |
5. Dashboard
Anmeldung
- E-Mail + Passwort — Standardanmeldung
- API Key — Direkte Eingabe eines API-Keys (für technische Nutzer)
- 2FA (TOTP) — Falls für den Account aktiviert, wird nach dem Passwort ein 6-stelliger Code abgefragt
Übersicht
Nach dem Login erscheint die Projekt-Übersicht mit allen zugänglichen Projekten als Kacheln. Jede Kachel zeigt:
- Rolle im Projekt (Viewer / Editor / Admin)
- Anzahl Environments und Variablen
- Datum des letzten Pushes
- Aktivitäts-Sparkline (Push-Häufigkeit der letzten 14 Tage)
Projektkontextmenü (⋯)
Jedes Projekt in der Sidebar hat ein Kontextmenü mit:
- 📦 Variablen
- 👥 Team
- 📋 Audit Log
- ⚙ Projekt-Einstellungen
- + Umgebung anlegen
- 🗑 Projekt löschen
Variablen
Environment über die Pills in der Topbar wechseln (per Drag & Drop sortierbar für Admins).
Pushen (↑ Push)
- Button ↑ Push in der Topbar
.env-Inhalt einfügen — oder Datei per Drag & Drop oder 📂 Datei laden verwenden- Pro Variable wählen, ob sie verschlüsselt gespeichert wird (Standard: ja)
- Optionale Commit-Nachricht eingeben
- ↑ Push klicken
Exportieren (⬇ Export ▾)
| Format | Beschreibung |
|---|---|
.env | Standard .env-Format (KEY=VALUE) |
| JSON | { "KEY": "value", … } |
| YAML | YAML-Mapping |
| K8s Secret | Kubernetes Secret-Manifest (Werte Base64-kodiert) |
Environment-Vergleich
Topbar → ⇄ Vergleich — zeigt zwei Environments nebeneinander:
- 🟢 Identisch
- 🔴 Nur in einer Env vorhanden
- 🟡 In beiden vorhanden, aber unterschiedlicher Wert
Versionshistorie
Topbar → 🕐 History — zeigt alle Versionen mit Zeitstempel, Autor und IP.
- Rollback ↩ — setzt die aktuelle Env auf den Stand dieser Version zurück
- ✎ Nachricht bearbeiten (Admin) — ändert die Commit-Nachricht nachträglich
Team-Verwaltung
Projekt → ⋯ → 👥 Team: Mitglieder hinzufügen, Rollen ändern, entfernen.
Einladungslink generieren (Admin): Zeitlich begrenzter Link (48h) — jeder mit dem Link kann dem Projekt mit der gewählten Rolle beitreten.
Projekt-Einstellungen
Projekt → ⋯ → ⚙ Projekt-Einstellungen:
- Environments: Schutz aktivieren, sperren, umbenennen, löschen, ⎘ Klonen
- IP-Allowlist: Beschränkt Zugriff auf bestimmte IP-Ranges (CIDR)
- Gefahrenzone: Projekt löschen (mit Namensbestätigung)
Ausstehende Versionen
Wenn eine Env als geschützt markiert ist, landen Pushes zunächst als pending und müssen von einem Admin genehmigt oder abgelehnt werden. Der Badge ⏳ Ausstehend erscheint in der Sidebar.
Einstellungen (Account)
Sidebar → ⚙ Einstellungen:
- Profil — Name, E-Mail, Firmenadresse
- Passwort ändern
- Zwei-Faktor-Authentifizierung (2FA) — TOTP aktivieren/deaktivieren
- Plan — aktueller Tarif und Limits
- API Keys — Keys anzeigen, erstellen, widerrufen, alle anderen Sessions beenden
- Anmelde-Protokoll — letzte 20 Anmeldeversuche mit Zeitstempel, IP und Ergebnis
6. CLI
Installation
cd envsync-cli
npm install
npm run build
# Global installieren (optional)
npm install -g .
Schnellstart
envsync login # Anmelden
envsync init # Projekt verknüpfen
envsync pull production # Variablen ziehen
envsync push staging --message "..." # Variablen pushen
Alle Befehle
Auth
envsync login # Anmelden (E-Mail/Passwort oder API-Key)
envsync logout # Gespeicherten API-Key löschen
envsync whoami # Aktuellen User und verknüpftes Projekt anzeigen
Projekt-Setup
envsync init # Aktuelles Verzeichnis verknüpfen
envsync init api-backend # Direkt mit Projekt-Slug verknüpfen
envsync projects # Alle zugänglichen Projekte auflisten
Variablen
# Pull — Variablen in lokale .env-Datei schreiben
envsync pull # Default-Env aus .envsync
envsync pull production # Bestimmte Env
envsync pull staging -f .env.local # In eigene Datei
envsync pull --dry-run # Vorschau ohne zu schreiben
envsync pull --no-mask # Geheime Werte unverschleiert zeigen
# Push — lokale .env-Datei hochladen
envsync push # Default-Env
envsync push production # Bestimmte Env
envsync push staging -m "Add API key" # Mit Commit-Nachricht
envsync push production -f .env.prod # Aus anderer Datei
envsync push production --yes # Bestätigung überspringen
# Diff
envsync diff # development → production
envsync diff staging production # Benutzerdefiniert
# Copy
envsync copy development staging --yes
History & Rollback
envsync history # Letzte 10 Versionen der Default-Env
envsync history production -n 25 # Mehr Versionen anzeigen
envsync rollback a1b2c3d4 # Rollback auf Version-ID
envsync rollback a1b2c3d4 staging # In bestimmter Env
Environments & API-Keys
envsync envs # Environments auflisten
envsync keys # Keys auflisten
envsync keys create "CI/CD Key" # Neuen Key erstellen
envsync keys revoke <key-id> # Key widerrufen
Befehle mit Variablen ausführen
envsync run production -- node server.js
envsync run staging -- npm test
envsync run -- python manage.py runserver
Projekt-Konfiguration (.envsync)
{
"project": "api-backend",
"defaultEnv": "development",
"envFile": ".env",
"apiUrl": "https://api.yourdomain.com"
}
Credential-Speicherung
Der API-Key wird in ~/.config/envsync/.credentials gespeichert (chmod 600). Die Variable ENVSYNC_API_KEY überschreibt den gespeicherten Key — ideal für CI/CD.
7. API-Referenz
Alle Endpunkte (sofern nicht anders angegeben) erfordern:
Authorization: Bearer esk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Health
GET /health → {"status": "ok", "version": "0.1.0"}
Auth
| Methode | Pfad | Beschreibung | Auth |
|---|---|---|---|
| POST | /v1/auth/register | Account registrieren | — |
| POST | /v1/auth/verify-email | E-Mail bestätigen | — |
| POST | /v1/auth/login | Anmelden (gibt api_key zurück) | — |
| POST | /v1/auth/forgot-password | Passwort-Reset anfordern | — |
| POST | /v1/auth/reset-password | Passwort zurücksetzen | — |
| POST | /v1/auth/totp/setup | TOTP-Secret generieren | ✓ |
| POST | /v1/auth/totp/enable | 2FA aktivieren | ✓ |
| POST | /v1/auth/totp/disable | 2FA deaktivieren | ✓ |
| POST | /v1/auth/totp/verify | TOTP-Code bei Login verifizieren | — |
| GET | /v1/auth/me | Eigene User-Daten | ✓ |
| PATCH | /v1/auth/profile | Profil aktualisieren | ✓ |
| POST | /v1/auth/change-password | Passwort ändern | ✓ |
| GET | /v1/auth/login-log | Anmelde-Protokoll | ✓ |
| GET | /v1/auth/keys | API-Keys auflisten | ✓ |
| POST | /v1/auth/keys | Neuen API-Key erstellen | ✓ |
| DELETE | /v1/auth/keys/:key_id | API-Key löschen | ✓ |
| POST | /v1/auth/keys/revoke-others | Alle anderen Keys widerrufen | ✓ |
| POST | /v1/auth/invite/accept | Einladungslink annehmen | ✓ |
Login-Response
{"api_key": "esk_...", "user": {"id": "...", "email": "...", "name": "..."}}
Bei aktivierter 2FA gibt Login zunächst {"requires_totp": true, "totp_session": "..."} zurück → dann POST /v1/auth/totp/verify mit {"totp_session": "...", "code": "123456"}.
Projekte
| Methode | Pfad | Rolle | Beschreibung |
|---|---|---|---|
| GET | /v1/projects | — | Alle eigenen Projekte |
| POST | /v1/projects | — | Neues Projekt erstellen |
| GET | /v1/projects/:slug | Viewer | Projekt-Details inkl. Environments |
| DELETE | /v1/projects/:slug | Admin | Projekt löschen |
| POST | /v1/projects/:slug/transfer | Admin | Projekt übertragen |
| GET | /v1/projects/:slug/audit | Admin | Audit-Log des Projekts |
| GET | /v1/projects/:slug/diff | Viewer | Environments vergleichen |
| GET | /v1/projects/:slug/activity | Viewer | Push-Aktivität (?days=7) |
| GET | /v1/projects/:slug/search | Viewer | Variablensuche (?q=DATABASE) |
| GET | /v1/projects/:slug/pending | Viewer | Ausstehende Versionen |
Mitglieder
| Methode | Pfad | Rolle | Beschreibung |
|---|---|---|---|
| GET | /v1/projects/:slug/members | Admin | Mitglieder auflisten |
| POST | /v1/projects/:slug/members | Admin | Mitglied hinzufügen |
| POST | /v1/projects/:slug/members/invite | Admin | Per E-Mail einladen |
| PATCH | /v1/projects/:slug/members/:user_id | Admin | Rolle ändern |
| DELETE | /v1/projects/:slug/members/:user_id | Admin | Mitglied entfernen |
| POST | /v1/projects/:slug/invite-link | Admin | Einladungslink generieren |
Environments
| Methode | Pfad | Rolle | Beschreibung |
|---|---|---|---|
| GET | /v1/projects/:slug/environments | Viewer | Environments auflisten |
| POST | /v1/projects/:slug/environments | Admin | Neue Env erstellen |
| PATCH | /v1/projects/:slug/environments/:env | Admin | Env umbenennen / schützen |
| DELETE | /v1/projects/:slug/environments/:env | Admin | Env löschen |
| PATCH | /v1/projects/:slug/environments/:env/lock | Admin | Env sperren/entsperren |
| POST | /v1/projects/:slug/environments/:env/clone | Admin | Env klonen |
| PATCH | /v1/projects/:slug/environments/order | Admin | Reihenfolge speichern |
| GET | /v1/projects/:slug/environments/:a/compare/:b | Viewer | Side-by-side-Vergleich |
Variablen
| Methode | Pfad | Rolle | Beschreibung |
|---|---|---|---|
| GET | /v1/projects/:slug/environments/:env/variables | Viewer | Aktuelle Variablen (entschlüsselt) |
| PUT | /v1/projects/:slug/environments/:env/variables | Editor | Variablen pushen |
Push-Body
{
"variables": { "KEY": "value", "SECRET": "s3cr3t" },
"message": "Add Stripe keys",
"secret_keys": ["SECRET"],
"descriptions": { "KEY": "Wofür wird das verwendet?" }
}
secret_keys — Liste der Keys, die verschlüsselt gespeichert werden sollen. Leer = alle verschlüsselt.
Versionen
| Methode | Pfad | Rolle | Beschreibung |
|---|---|---|---|
| GET | /v1/projects/:slug/environments/:env/history | Viewer | Versionshistorie |
| GET | /v1/projects/:slug/environments/:env/history/:id | Viewer | Versions-Detail |
| POST | /v1/projects/:slug/environments/:env/rollback | Editor | Rollback |
| PATCH | /v1/projects/:slug/environments/:env/versions/:id | Admin | Nachricht bearbeiten |
| POST | /v1/projects/:slug/environments/:env/versions/:id/approve | Admin | Pending-Version genehmigen |
| POST | /v1/projects/:slug/environments/:env/versions/:id/reject | Admin | Pending-Version ablehnen |
IP-Allowlist
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /v1/projects/:slug/ip-allowlist | Einträge auflisten |
| POST | /v1/projects/:slug/ip-allowlist | Eintrag hinzufügen ({"cidr": "192.168.1.0/24", "note": "..."}) |
| DELETE | /v1/projects/:slug/ip-allowlist/:entry_id | Eintrag löschen |
Webhooks
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /v1/projects/:slug/webhooks | Webhooks auflisten |
| POST | /v1/projects/:slug/webhooks | Webhook erstellen |
| DELETE | /v1/projects/:slug/webhooks/:id | Webhook löschen |
Events: * (alle), variables.pushed, variables.rollback, member.added
{
"event": "variables.pushed",
"project": "api-backend",
"environment": "production",
"version": "a1b2c3d4",
"author": "jan@acme.com",
"timestamp": "2026-05-08T12:34:56Z"
}
Admin (Superuser only)
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /v1/admin/stats | Systemstatistiken |
| GET | /v1/admin/users | Alle User |
| PATCH | /v1/admin/users/:id | User sperren/entsperren, Plan setzen, Superuser |
| DELETE | /v1/admin/users/:id | User löschen |
| GET | /v1/admin/projects | Alle Projekte |
| GET | /v1/admin/audit | Globales Audit-Log |
| GET | /v1/admin/plan-limits | Plan-Limits anzeigen |
| PATCH | /v1/admin/plan-limits | Plan-Limits überschreiben |
| GET | /v1/admin/settings | Systemeinstellungen |
| PATCH | /v1/admin/settings | Systemeinstellungen ändern |
| POST | /v1/admin/rotate-master-key | Master Key rotieren |
| GET | /v1/admin/backup | Datenbank-Backup herunterladen |
8. Berechtigungen (RBAC)
| Aktion | Viewer | Editor | Admin |
|---|---|---|---|
| Variablen lesen | ✓ | ✓ | ✓ |
| Variablen exportieren | ✓ | ✓ | ✓ |
| History und Diff | ✓ | ✓ | ✓ |
| Environment-Vergleich | ✓ | ✓ | ✓ |
| Variablensuche | ✓ | ✓ | ✓ |
| Variablen pushen | — | ✓ | ✓ |
| Rollback | — | ✓ | ✓ |
| Zwischen Envs kopieren | — | ✓ | ✓ |
| Environments verwalten | — | — | ✓ |
| Env sperren / schützen | — | — | ✓ |
| Env klonen | — | — | ✓ |
| Mitglieder verwalten | — | — | ✓ |
| Einladungslinks generieren | — | — | ✓ |
| Webhooks verwalten | — | — | ✓ |
| IP-Allowlist verwalten | — | — | ✓ |
| Audit Log lesen | — | — | ✓ |
| Pending-Versionen genehmigen | — | — | ✓ |
| Projekt löschen / übertragen | — | — | ✓ |
- Projekt-Eigentümer erhalten automatisch die Admin-Rolle.
- Superuser haben Zugriff auf das Admin-Panel und können alle Projekte und User verwalten.
- Nicht-Mitglieder erhalten bei Projekt-Endpunkten immer
404(nicht403), um das Vorhandensein des Projekts nicht zu verraten.
9. Sicherheit
Verschlüsselung
Alle Variablenwerte werden mit AES-256-GCM verschlüsselt gespeichert:
- Jeder Wert bekommt eine zufällige 12-Byte-Nonce
- Schlüssel:
ENVSYNC_MASTER_KEY(32 Bytes, Base64) - Ciphertext + Nonce werden Base64-kodiert in der Datenbank gespeichert
- Der Plaintext verlässt die API nur bei authentifizierten GET-Requests
API-Keys
- Präfix
esk_+ 32 zufällige Bytes (Base64url) - Nur der SHA-256-Hash wird in der Datenbank gespeichert
- Plaintext wird exakt einmal zurückgegeben (bei Erstellung)
- Bei E-Mail/Passwort-Login werden alte Session-Keys automatisch gelöscht, bevor ein neuer erstellt wird
Secret Scanning
Beim Push scannt die API automatisch alle Werte auf bekannte Secret-Patterns (AWS Keys, GitHub Tokens, Stripe Keys, Slack Tokens, private Keys, Passwörter in URLs). Verdächtige Werte werden markiert — der Push wird nicht blockiert.
IP-Allowlisting
Pro Projekt kann eine Allowlist von IP-Ranges (CIDR) konfiguriert werden. Bei gesetzter Allowlist dürfen nur IPs aus diesen Ranges Variablen lesen oder pushen. Andere IPs erhalten 403.
Zwei-Faktor-Authentifizierung
TOTP-basierte 2FA (RFC 6238). Kompatibel mit Google Authenticator, Authy, 1Password, etc.
Rate Limiting
In-Memory Token-Bucket pro IP. Standard: 600 Requests / 60 Sekunden. Konfigurierbar über ENVSYNC_RATE_LIMIT und ENVSYNC_RATE_WINDOW.
10. Administration
Admin-Panel
Superuser sehen in der Sidebar den Eintrag 🛡 Admin mit vier Tabs:
- Benutzer: Alle User anzeigen, sperren/entsperren, Superuser-Status, Plan setzen, löschen
- Projekte: Alle Projekte anzeigen, Eigentümer wechseln
- Logs: Globales Audit-Log über alle Projekte
- Einstellungen: Plan-Limits, Registrierung, Master Key rotieren, Datenbank-Backup
User anlegen (CLI-Helfer)
make create-user EMAIL=jan@acme.com NAME="Jan Koch"
Superuser setzen
docker compose exec api python3 -c "
import src.db.repository as r
r.set_superuser('admin@yourdomain.com', True)
"
Master Key Rotation
Admin-Panel → Einstellungen → ⟳ Master-Key rotieren: Alle Werte werden re-encryptiert. Den neuen Key in .env eintragen und den Server neu starten.
11. CI/CD-Integration
GitHub Actions
- name: ENV Sync — Pull production variables
env:
ENVSYNC_API_KEY: ${{ secrets.ENVSYNC_API_KEY }}
ENVSYNC_API_URL: https://api.yourdomain.com
run: |
npx envsync pull production
Direkte API-Nutzung
curl -s \
-H "Authorization: Bearer $ENVSYNC_API_KEY" \
"https://api.yourdomain.com/v1/projects/api-backend/environments/production/variables"
[
{ "key": "DATABASE_URL", "value": "postgres://...", "encrypted": true },
{ "key": "PORT", "value": "3000", "encrypted": false }
]
12. Backup & Wiederherstellung
Via Dashboard
Admin-Panel → Einstellungen → ⬇ Backup herunterladen — lädt einen konsistenten SQLite-Snapshot herunter (ohne Server-Downtime, via SQLite Backup API).
Manuelles Backup
# Via Makefile
make backup
# → backup_20260508_143022.db
# Manuell
docker compose exec api python3 -c "
import sqlite3
src = sqlite3.connect('/data/envsync.db')
dst = sqlite3.connect('/tmp/backup.db')
src.backup(dst); dst.close()
"
docker compose cp api:/tmp/backup.db ./backup.db
Wiederherstellung
make restore FILE=backup_20260508_143022.db
# Oder manuell:
docker compose down
docker run --rm -v envsync-deploy_api-data:/data \
-v $(pwd):/backup alpine \
cp /backup/backup_20260508_143022.db /data/envsync.db
docker compose up -d
Automatische Backups (Cron)
0 3 * * * cd /opt/envsync && make backup >> /var/log/envsync-backup.log 2>&1