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

2. Architektur

Browser / CLI │ ▼ Caddy (TLS, Port 443) │ ├─→ api.domain.com ──→ API-Container :3001 │ │ │ SQLite /data/envsync.db │ (Docker Volume, persistent) │ └─→ app.domain.com ──→ Dashboard-Container (Nginx :80) │ Statisches index.html (macht API-Calls direkt vom Browser)

Drei Komponenten

KomponenteTechnologieBeschreibung
envsync-apiPython 3.12, stdlib-only + cryptographyREST-API, SQLite, eigenes HTTP-Framework
envsync-dashboardVanilla JS, Single-HTML-FileSPA ohne Framework, wird von Nginx ausgeliefert
envsync-cliTypeScript / Node.js, zero external depsKommandozeilen-Client

Datenbankschema (SQLite)

users ──────────── api_keys │ subscriptions │ login_log │ └── projects ─── project_members (user ↔ project + role) │ project_ip_allowlist │ webhooks │ └── environments ──── variable_versions (append-only) └── variable_values (encrypted) audit_log

3. Installation & Erststart

Voraussetzungen

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

VariableBeschreibung
ENVSYNC_MASTER_KEYAES-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

VariableStandardBeschreibung
ENVSYNC_DEMO_EMAILdemo@envsync.devE-Mail des Seed-Admins
ENVSYNC_DEMO_KEYzufälligFester API-Key für Seed-Admin
ENVSYNC_DBenvsync.dbPfad zur SQLite-Datenbankdatei
ENVSYNC_REGISTRATION_DISABLEDfalseOffene Registrierung deaktivieren
ENVSYNC_APP_URLhttp://localhost:28080Öffentliche Dashboard-URL (für E-Mail-Links)
PORT3001API-Listening-Port
HOST0.0.0.0API-Listening-Host
ENVSYNC_RATE_LIMIT600Max. Requests pro Zeitfenster pro IP
ENVSYNC_RATE_WINDOW60Zeitfenster in Sekunden

E-Mail (SMTP)

VariableBeschreibung
SMTP_HOSTSMTP-Server (z.B. smtp.postmarkapp.com)
SMTP_PORTPort (Standard: 587)
SMTP_USERSMTP-Benutzername
SMTP_PASSWORDSMTP-Passwort
SMTP_FROMAbsender-Adresse
Ohne SMTP-Konfiguration werden Verifizierungs- und Einladungslinks in die API-Logs geschrieben (Dev-Modus).

Stripe (optional)

VariableBeschreibung
STRIPE_SECRET_KEYStripe Secret Key
STRIPE_WEBHOOK_SECRETStripe Webhook Signing Secret
STRIPE_TEAM_PRICE_IDStripe Price ID für Team-Plan
STRIPE_ENT_PRICE_IDStripe Price ID für Enterprise-Plan

CLI-Umgebungsvariablen

VariableBeschreibung
ENVSYNC_API_KEYAPI-Key override (für CI/CD ohne interaktiven Login)
ENVSYNC_API_URLAPI-URL override (überschreibt .envsync-Konfiguration)

5. Dashboard

Anmeldung

Übersicht

Nach dem Login erscheint die Projekt-Übersicht mit allen zugänglichen Projekten als Kacheln. Jede Kachel zeigt:

Projektkontextmenü (⋯)

Jedes Projekt in der Sidebar hat ein Kontextmenü mit:

Variablen

Environment über die Pills in der Topbar wechseln (per Drag & Drop sortierbar für Admins).

Pushen (↑ Push)

  1. Button ↑ Push in der Topbar
  2. .env-Inhalt einfügen — oder Datei per Drag & Drop oder 📂 Datei laden verwenden
  3. Pro Variable wählen, ob sie verschlüsselt gespeichert wird (Standard: ja)
  4. Optionale Commit-Nachricht eingeben
  5. ↑ Push klicken

Exportieren (⬇ Export ▾)

FormatBeschreibung
.envStandard .env-Format (KEY=VALUE)
JSON{ "KEY": "value", … }
YAMLYAML-Mapping
K8s SecretKubernetes Secret-Manifest (Werte Base64-kodiert)

Environment-Vergleich

Topbar → ⇄ Vergleich — zeigt zwei Environments nebeneinander:

Versionshistorie

Topbar → 🕐 History — zeigt alle Versionen mit Zeitstempel, Autor und IP.

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:

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:

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"
}
Diese Datei kann bedenkenlos in Git eingecheckt werden — sie enthält keine Secrets.

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

MethodePfadBeschreibungAuth
POST/v1/auth/registerAccount registrieren
POST/v1/auth/verify-emailE-Mail bestätigen
POST/v1/auth/loginAnmelden (gibt api_key zurück)
POST/v1/auth/forgot-passwordPasswort-Reset anfordern
POST/v1/auth/reset-passwordPasswort zurücksetzen
POST/v1/auth/totp/setupTOTP-Secret generieren
POST/v1/auth/totp/enable2FA aktivieren
POST/v1/auth/totp/disable2FA deaktivieren
POST/v1/auth/totp/verifyTOTP-Code bei Login verifizieren
GET/v1/auth/meEigene User-Daten
PATCH/v1/auth/profileProfil aktualisieren
POST/v1/auth/change-passwordPasswort ändern
GET/v1/auth/login-logAnmelde-Protokoll
GET/v1/auth/keysAPI-Keys auflisten
POST/v1/auth/keysNeuen API-Key erstellen
DELETE/v1/auth/keys/:key_idAPI-Key löschen
POST/v1/auth/keys/revoke-othersAlle anderen Keys widerrufen
POST/v1/auth/invite/acceptEinladungslink 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

MethodePfadRolleBeschreibung
GET/v1/projectsAlle eigenen Projekte
POST/v1/projectsNeues Projekt erstellen
GET/v1/projects/:slugViewerProjekt-Details inkl. Environments
DELETE/v1/projects/:slugAdminProjekt löschen
POST/v1/projects/:slug/transferAdminProjekt übertragen
GET/v1/projects/:slug/auditAdminAudit-Log des Projekts
GET/v1/projects/:slug/diffViewerEnvironments vergleichen
GET/v1/projects/:slug/activityViewerPush-Aktivität (?days=7)
GET/v1/projects/:slug/searchViewerVariablensuche (?q=DATABASE)
GET/v1/projects/:slug/pendingViewerAusstehende Versionen

Mitglieder

MethodePfadRolleBeschreibung
GET/v1/projects/:slug/membersAdminMitglieder auflisten
POST/v1/projects/:slug/membersAdminMitglied hinzufügen
POST/v1/projects/:slug/members/inviteAdminPer E-Mail einladen
PATCH/v1/projects/:slug/members/:user_idAdminRolle ändern
DELETE/v1/projects/:slug/members/:user_idAdminMitglied entfernen
POST/v1/projects/:slug/invite-linkAdminEinladungslink generieren

Environments

MethodePfadRolleBeschreibung
GET/v1/projects/:slug/environmentsViewerEnvironments auflisten
POST/v1/projects/:slug/environmentsAdminNeue Env erstellen
PATCH/v1/projects/:slug/environments/:envAdminEnv umbenennen / schützen
DELETE/v1/projects/:slug/environments/:envAdminEnv löschen
PATCH/v1/projects/:slug/environments/:env/lockAdminEnv sperren/entsperren
POST/v1/projects/:slug/environments/:env/cloneAdminEnv klonen
PATCH/v1/projects/:slug/environments/orderAdminReihenfolge speichern
GET/v1/projects/:slug/environments/:a/compare/:bViewerSide-by-side-Vergleich

Variablen

MethodePfadRolleBeschreibung
GET/v1/projects/:slug/environments/:env/variablesViewerAktuelle Variablen (entschlüsselt)
PUT/v1/projects/:slug/environments/:env/variablesEditorVariablen 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

MethodePfadRolleBeschreibung
GET/v1/projects/:slug/environments/:env/historyViewerVersionshistorie
GET/v1/projects/:slug/environments/:env/history/:idViewerVersions-Detail
POST/v1/projects/:slug/environments/:env/rollbackEditorRollback
PATCH/v1/projects/:slug/environments/:env/versions/:idAdminNachricht bearbeiten
POST/v1/projects/:slug/environments/:env/versions/:id/approveAdminPending-Version genehmigen
POST/v1/projects/:slug/environments/:env/versions/:id/rejectAdminPending-Version ablehnen

IP-Allowlist

MethodePfadBeschreibung
GET/v1/projects/:slug/ip-allowlistEinträge auflisten
POST/v1/projects/:slug/ip-allowlistEintrag hinzufügen ({"cidr": "192.168.1.0/24", "note": "..."})
DELETE/v1/projects/:slug/ip-allowlist/:entry_idEintrag löschen

Webhooks

MethodePfadBeschreibung
GET/v1/projects/:slug/webhooksWebhooks auflisten
POST/v1/projects/:slug/webhooksWebhook erstellen
DELETE/v1/projects/:slug/webhooks/:idWebhook 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)

MethodePfadBeschreibung
GET/v1/admin/statsSystemstatistiken
GET/v1/admin/usersAlle User
PATCH/v1/admin/users/:idUser sperren/entsperren, Plan setzen, Superuser
DELETE/v1/admin/users/:idUser löschen
GET/v1/admin/projectsAlle Projekte
GET/v1/admin/auditGlobales Audit-Log
GET/v1/admin/plan-limitsPlan-Limits anzeigen
PATCH/v1/admin/plan-limitsPlan-Limits überschreiben
GET/v1/admin/settingsSystemeinstellungen
PATCH/v1/admin/settingsSystemeinstellungen ändern
POST/v1/admin/rotate-master-keyMaster Key rotieren
GET/v1/admin/backupDatenbank-Backup herunterladen

8. Berechtigungen (RBAC)

AktionViewerEditorAdmin
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

9. Sicherheit

Verschlüsselung

Alle Variablenwerte werden mit AES-256-GCM verschlüsselt gespeichert:

Wichtig: Ohne den Master Key sind alle gespeicherten Secrets unlesbar.

API-Keys

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:

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
Wichtig: Master Key und Datenbank immer gemeinsam sichern — ohne den Key ist die Datenbank unlesbar.