Übersicht
Plugin für Revela, das die generierte Website per SFTP auf einen Webserver synchronisiert. Zielgruppe: Fotografen, nicht Sysadmins.
Entwicklungsrechner Webserver
┌─────────────────┐ SFTP ┌──────────────────────────┐
│ revela generate │ Ed25519 Key │ /var/www/photos/ │
│ revela deploy │ ──────────────────>│ index.html │
│ │ │ images/ │
│ IPathResolver │ │ css/ │
│ .OutputPath │ │ │
└─────────────────┘ └──────────────────────────┘
Commands
| Command |
Beschreibung |
revela deploy init |
Interaktiver Setup-Wizard (Spectre.Console) |
revela deploy sftp |
Deployment ausführen |
revela deploy sftp --dry-run |
Trockenlauf (zeigt was passieren würde) |
revela deploy sftp --delete-orphans |
Verwaiste Dateien auf Server löschen |
- Parent Command:
deploy
deploy sftp ist IsSequentialStep für revela deploy all (eigene Kette, nicht Teil von generate all)
Konfiguration
{
"Spectara.Revela.Plugins.Deploy.Sftp": {
"Host": "photos.example.com",
"Port": 22,
"Username": "deploy",
"KeyFile": "~/.ssh/id_ed25519",
"RemotePath": "/var/www/photos",
"DeleteOrphans": false,
"MaxParallelUploads": 4
}
}
| Option |
Typ |
Default |
Beschreibung |
Host |
string |
required |
Hostname oder IP |
Port |
int |
22 |
SSH-Port |
Username |
string |
required |
SSH-Benutzername |
KeyFile |
string |
~/.ssh/id_ed25519 |
Pfad zum privaten SSH-Key |
RemotePath |
string |
required |
Zielverzeichnis auf dem Server |
DeleteOrphans |
bool |
false |
Verwaiste Dateien auf Server löschen |
MaxParallelUploads |
int |
4 |
Gleichzeitige SFTP-Transfers |
IOptions<T> mit ValidateDataAnnotations() + ValidateOnStart()
~-Expansion cross-platform via Environment.GetFolderPath(SpecialFolder.UserProfile)
- Config Section Name: volle Package-ID (
Spectara.Revela.Plugins.Deploy.Sftp)
Authentifizierung
Key-only. Kein Passwort. Nie.
- Kein Passwort in Config, kein Passwort als CLI-Option
- Ed25519 bevorzugt, SSH.NET unterstützt alle gängigen Key-Formate
- Key-Generierung via
ssh-keygen Prozessaufruf (auf allen Plattformen vorhanden)
Setup-Wizard (deploy init)
$ revela deploy init
📡 Deploy Setup
? Server-Adresse: photos.example.com
? SSH Port [22]: 22
? Benutzername: deploy
? Zielverzeichnis: /var/www/photos
🔑 SSH Key Setup
Kein SSH-Key gefunden.
● Neuen Key erstellen (empfohlen)
○ Vorhandenen Key verwenden
○ Key-Pfad manuell angeben
✓ Key erstellt: ~/.ssh/id_ed25519
📋 Diesen Key auf dem Server hinterlegen:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... revela-deploy
Der Key wurde auch in die Zwischenablage kopiert.
? Verbindung testen? [Ja]
✓ Verbindung erfolgreich!
✓ Konfiguration gespeichert in project.json
Projekt-Wizard Integration
Das Plugin registriert einen optionalen IWizardStep für den Projekt-Setup-Wizard (revela project create):
public sealed class DeployWizardStep : IWizardStep
{
public string Name => "SFTP Deploy";
public string Description => "Website auf Server veröffentlichen";
public int Order => 110; // Nach OneDrive (100)
public bool IsRequired => false;
}
Erscheint am Ende des Wizards in der optionalen Features-Auswahl:
Optionale Features einrichten:
[x] OneDrive Source
[x] SFTP Deploy
[ ] ...
Bei Auswahl: gleicher Flow wie deploy init (Server, Port, Username, Key-Check, Verbindungstest). Kann jederzeit nachträglich via revela deploy init eingerichtet werden.
Delta-Sync Strategie
rsync-Ansatz: Größe + mtime, kein lokales State-File.
- Remote-Verzeichnis rekursiv listen (
SftpClient.ListDirectory())
- Lokales Output-Verzeichnis listen (
IPathResolver.OutputPath)
- Vergleichen: Größe + mtime
- Nur geänderte/neue Dateien hochladen (parallel, Default: 4)
- Nach Upload: mtime auf Remote setzen (
SftpClient.SetAttributes())
- Optional: Orphans auf Remote löschen (
--delete-orphans / Config)
Designprinzip: False positive (unnötig übertragen) = akzeptabel. False negative (Änderung nicht erkannt) = Bug.
Implizites Resume: Nach Abbruch erkennt der nächste Lauf automatisch was noch fehlt — kein State-File, kein spezieller Resume-Modus.
Fortschrittsanzeige
Spectre.Console, zwei Phasen:
- Scan-Phase: Status Spinner — Remote + Lokal vergleichen, Delta berechnen
- Upload-Phase: Progress Bar — Dateien hochladen mit Zähler + Dateiname
Standalone Build
Das Plugin wird im Full-Standalone-Build mitgeliefert (wie Serve, Compress, OneDrive). Eintrag in build-standalone.ps1:
@{ Project = "src/Plugins/Deploy/Sftp/Sftp.csproj"; PackageId = "Spectara.Revela.Plugins.Deploy.Sftp" }
Kein extra revela plugin install nötig — jeder Fotograf der Revela runterlädt hat Deploy direkt verfügbar.
Technische Entscheidungen
| Thema |
Entscheidung |
Begründung |
| Library |
SSH.NET 2025.1.0 |
Pure .NET, MIT, 260M DL, zero transitive deps, bereits im Projekt |
| Sync-Lib |
Keine — selbst gebaut |
Nichts passendes auf NuGet, ~100 Zeilen Code |
| Source-Dir |
IPathResolver.OutputPath |
Nie hardcoded |
| Verzeichnisse |
Automatisch anlegen |
SftpClient.CreateDirectory() wenn nötig |
| Symlinks |
Ignorieren |
Sollten im Output nicht vorkommen |
| Berechtigungen |
Nicht setzen |
Server-Default (644/755) reicht für nginx/IIS |
| Exclude |
Hardcoded Junk-Liste |
.DS_Store, Thumbs.db, desktop.ini, .gitkeep, .gitignore |
Scope
v1
Bewusst draußen
Passwort-Auth → Sicherheitsrisiko, Passwörter in Config landen in Git
Mehrere Targets → Ein Projekt = ein Ziel, mehrere Projekte für mehrere Sites
Deploy Hooks → Zielgruppe (Fotografen) braucht das nicht
Bandwidth Limit → Bei Bedarf später
Resume-Logik → Implizit durch Delta-Sync
Konfigurierbare Excludes → Hardcoded Junk-Liste reicht für v1
Dateiberechtigungen setzen → Server-Default reicht
Übersicht
Plugin für Revela, das die generierte Website per SFTP auf einen Webserver synchronisiert. Zielgruppe: Fotografen, nicht Sysadmins.
Commands
revela deploy initrevela deploy sftprevela deploy sftp --dry-runrevela deploy sftp --delete-orphansdeploydeploy sftpistIsSequentialStepfürrevela deploy all(eigene Kette, nicht Teil vongenerate all)Konfiguration
{ "Spectara.Revela.Plugins.Deploy.Sftp": { "Host": "photos.example.com", "Port": 22, "Username": "deploy", "KeyFile": "~/.ssh/id_ed25519", "RemotePath": "/var/www/photos", "DeleteOrphans": false, "MaxParallelUploads": 4 } }HostPort22UsernameKeyFile~/.ssh/id_ed25519RemotePathDeleteOrphansfalseMaxParallelUploads4IOptions<T>mitValidateDataAnnotations()+ValidateOnStart()~-Expansion cross-platform viaEnvironment.GetFolderPath(SpecialFolder.UserProfile)Spectara.Revela.Plugins.Deploy.Sftp)Authentifizierung
Key-only. Kein Passwort. Nie.
ssh-keygenProzessaufruf (auf allen Plattformen vorhanden)Setup-Wizard (
deploy init)Projekt-Wizard Integration
Das Plugin registriert einen optionalen
IWizardStepfür den Projekt-Setup-Wizard (revela project create):Erscheint am Ende des Wizards in der optionalen Features-Auswahl:
Bei Auswahl: gleicher Flow wie
deploy init(Server, Port, Username, Key-Check, Verbindungstest). Kann jederzeit nachträglich viarevela deploy initeingerichtet werden.Delta-Sync Strategie
rsync-Ansatz: Größe + mtime, kein lokales State-File.
SftpClient.ListDirectory())IPathResolver.OutputPath)SftpClient.SetAttributes())--delete-orphans/ Config)Designprinzip: False positive (unnötig übertragen) = akzeptabel. False negative (Änderung nicht erkannt) = Bug.
Implizites Resume: Nach Abbruch erkennt der nächste Lauf automatisch was noch fehlt — kein State-File, kein spezieller Resume-Modus.
Fortschrittsanzeige
Spectre.Console, zwei Phasen:
Standalone Build
Das Plugin wird im Full-Standalone-Build mitgeliefert (wie Serve, Compress, OneDrive). Eintrag in
build-standalone.ps1:Kein extra
revela plugin installnötig — jeder Fotograf der Revela runterlädt hat Deploy direkt verfügbar.Technische Entscheidungen
IPathResolver.OutputPathSftpClient.CreateDirectory()wenn nötig.DS_Store,Thumbs.db,desktop.ini,.gitkeep,.gitignoreScope
v1
IPlugin, Config, DI)deploy init— Interaktiver Setup-Wizarddeploy sftp+--dry-run+--delete-orphansIWizardStep, optional)Bewusst draußen
Passwort-Auth→ Sicherheitsrisiko, Passwörter in Config landen in GitMehrere Targets→ Ein Projekt = ein Ziel, mehrere Projekte für mehrere SitesDeploy Hooks→ Zielgruppe (Fotografen) braucht das nichtBandwidth Limit→ Bei Bedarf späterResume-Logik→ Implizit durch Delta-SyncKonfigurierbare Excludes→ Hardcoded Junk-Liste reicht für v1Dateiberechtigungen setzen→ Server-Default reicht