Skip to content

feat(plugin): Deploy SFTP — Website per SFTP auf Server synchronisieren #37

@kirkone

Description

@kirkone

Ü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.

  1. Remote-Verzeichnis rekursiv listen (SftpClient.ListDirectory())
  2. Lokales Output-Verzeichnis listen (IPathResolver.OutputPath)
  3. Vergleichen: Größe + mtime
  4. Nur geänderte/neue Dateien hochladen (parallel, Default: 4)
  5. Nach Upload: mtime auf Remote setzen (SftpClient.SetAttributes())
  6. 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:

  1. Scan-Phase: Status Spinner — Remote + Lokal vergleichen, Delta berechnen
  2. 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

  • Plugin-Grundstruktur (IPlugin, Config, DI)
  • deploy init — Interaktiver Setup-Wizard
  • deploy sftp + --dry-run + --delete-orphans
  • Key-only Auth (Ed25519 bevorzugt)
  • Delta-Sync (Größe + mtime, rsync-Ansatz)
  • Parallele Uploads (konfigurierbar, Default: 4)
  • Fortschrittsanzeige (Spectre.Console)
  • Projekt-Wizard Integration (IWizardStep, optional)
  • Standalone Build Integration
  • Cross-platform (Windows, Linux, macOS)
  • Sicherheitsdoku (dedizierter Deploy-User)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions