Self-hosted · .NET 10 · MITSelbst gehostet · .NET 10 · MIT

A visual AppHost — and a place to run it.

Ein sichtbarer AppHost — und ein Ort, an dem er läuft.

AspireUI draws a .NET Aspire AppHost as a graph, writes the C# while you edit it, starts it, and keeps what gets deployed running on hardware you own.

AspireUI zeichnet einen .NET-Aspire-AppHost als Graph, schreibt den C#-Code beim Bearbeiten mit, startet ihn und hält das, was deployt wurde, auf eigener Hardware am Laufen.

It is a browser application. On the host it needs Docker — nothing else, not even the SDK: the image carries the .NET SDK, the Docker CLI and the aspire CLI, because the features that run and host stacks depend on all three.

Es ist eine Browser-Anwendung. Auf dem Host braucht es Docker — sonst nichts, nicht einmal das SDK: Das Image bringt .NET-SDK, Docker-CLI und die aspire-CLI mit, weil die Funktionen zum Starten und Hosten alle drei brauchen.

docker run -d --name aspireui -p 8080:8080 \
  -v aspireui-data:/data \
  -v /var/run/docker.sock:/var/run/docker.sock \
  ghcr.io/fgilde/aspireui:latest
ghcr.io/fgilde/aspireui· 167 catalog apps167 Katalog-Apps· no account, no cloudkein Konto, keine Cloud
Program.cs
+

      

// drag a node, add one, remove one — the C# follows

// Knoten ziehen, hinzufügen, entfernen — der C#-Code folgt

01

The canvas is the AppHost

Der Canvas ist der AppHost

Not a picture of one. The add-resource dialog is generated from a reflection pass over the Aspire integrations the project references, so an integration you install shows up with its real parameters and its real capabilities — there is no hand-maintained list here to go stale.

Kein Bild davon. Der Dialog zum Hinzufügen von Ressourcen entsteht per Reflection über die Aspire-Integrationen, die das Projekt referenziert: Eine neu installierte Integration erscheint mit ihren echten Parametern und Fähigkeiten — hier gibt es keine handgepflegte Liste, die veralten kann.

The property grid edits those parameters. Reference pickers only offer resources whose type fits, and offer to create a missing dependency on the spot. Composite helpers such as AddObservabilityStack, which set up several resources at once, are discovered the same way and grouped separately.

Das Property-Grid bearbeitet diese Parameter. Referenz-Picker zeigen nur Ressourcen mit passendem Typ und bieten an, eine fehlende Abhängigkeit direkt anzulegen. Zusammengesetzte Helfer wie AddObservabilityStack, die mehrere Ressourcen auf einmal aufsetzen, werden genauso gefunden und separat gruppiert.

The code panel is not a preview you read at the end. Monaco with Roslyn-backed IntelliSense edits the same file, and an edit is parsed back into the graph — the two cannot drift apart, which is the whole reason to trust either.

Das Code-Panel ist keine Vorschau, die man am Ende liest. Monaco mit Roslyn-gestütztem IntelliSense bearbeitet dieselbe Datei, und eine Änderung wird zurück in den Graph geparst — beide können nicht auseinanderlaufen, und genau deshalb kann man beiden trauen.

The AspireUI editor: canvas, property grid and generated C#
Editor — palette, canvas, property grid, generated Program.cs
Editor — Palette, Canvas, Property-Grid, generierte Program.cs
02

Run it, and the drawing stops being a drawing

Starten — und die Zeichnung ist keine Zeichnung mehr

Live resource state on the canvas while a stack runs
A running stack — state, endpoints and the child resources a builder spawned
Ein laufender Stack — Zustand, Endpunkte und die Kind-Ressourcen eines Builders

Run starts the stack through the Aspire CLI and links straight into the Aspire dashboard. While it is up, each node on the canvas shows the state Aspire itself reports, the endpoint URLs it was given, and the child resources a builder created underneath it — a volume or a container you never wrote down becomes visible instead of implied. Console output streams per resource.

Run startet den Stack über die Aspire-CLI und verlinkt direkt ins Aspire-Dashboard. Solange er läuft, zeigt jeder Knoten den Zustand, den Aspire selbst meldet, die Endpunkt-URLs, die er bekommen hat, und die Kind-Ressourcen, die ein Builder darunter erzeugt hat — ein Volume oder Container, den man nie hingeschrieben hat, wird sichtbar statt nur implizit. Konsolenausgabe streamt pro Ressource.

  • PublishDocker Compose, Kubernetes (Helm), Azure Bicep or the Aspire manifest — read the artifact, download the bundle, or deploy Compose right there.Docker Compose, Kubernetes (Helm), Azure Bicep oder das Aspire-Manifest — Artefakt ansehen, Bundle herunterladen oder Compose direkt deployen.
  • ImportAn existing AppHost from .cs, .csproj or a .zip, a folder, a git repository, or a docker-compose.yml.Ein bestehender AppHost aus .cs, .csproj oder .zip, ein Ordner, ein Git-Repository oder eine docker-compose.yml.
  • AssistantAn OpenAI-compatible endpoint (Ollama and friends included) rewrites the stack on the canvas — and, outside the editor, operates the instance through the same permission-checked tools the MCP server exposes.Ein OpenAI-kompatibler Endpunkt (Ollama und Co. eingeschlossen) schreibt den Stack auf dem Canvas um — und bedient außerhalb des Editors die Instanz über dieselben rechteprüfenden Tools, die auch der MCP-Server anbietet.
03

A stack you keep is more than a process

Ein Stack, den man behält, ist mehr als ein Prozess

Hosting deploys a stack as a tracked appliance. It gets a URL, a state you can see, start / stop / update, volume backups on a schedule with retention, resource limits and a healthcheck written into the generated Compose file, and a menu for the things you otherwise do over SSH: browse and edit its files, open a real shell in the container, look at a diff before an update touches anything.

Hosting deployt einen Stack als verwaltete Appliance. Er bekommt eine URL, einen sichtbaren Zustand, Start / Stop / Update, Volume-Backups nach Zeitplan samt Aufbewahrung, Ressourcen-Limits und einen Healthcheck in der generierten Compose-Datei — und ein Menü für das, was man sonst über SSH macht: Dateien ansehen und bearbeiten, eine echte Shell im Container öffnen, vor einem Update erst den Diff lesen.

An app from the store arrives with its volumes, ports, companion databases and a freshly generated secret already wired. Each one is a single JSON file, which is why adding your own is a URL or a pull request rather than a release of ours to wait for.

Eine App aus dem Store kommt mit Volumes, Ports, Begleit-Datenbanken und einem frisch erzeugten Secret bereits verdrahtet an. Jede ist eine einzige JSON-Datei; deshalb ist eine eigene hinzuzufügen eine URL oder ein Pull Request und kein Warten auf ein Release von uns.

Not only on this machine, and not only once: an app can be installed onto several targets at once, and a running one can be moved or copied — with its data — from one target to another.

Nicht nur auf dieser Maschine und nicht nur einmal: Eine App kann auf mehrere Ziele gleichzeitig installiert werden, und eine laufende lässt sich — samt Daten — von einem Ziel auf ein anderes verschieben oder kopieren.

  • TargetsZieleThis machine · another box over SSH · a Docker daemon over TCP with mTLS · Kubernetes via Helm · Azure Container Apps · Cloud Run · ECS. Machines at Hetzner, DigitalOcean, Linode, AWS, Azure and GCP can be created from inside AspireUI.Diese Maschine · eine andere Kiste über SSH · ein Docker-Daemon über TCP mit mTLS · Kubernetes per Helm · Azure Container Apps · Cloud Run · ECS. Maschinen bei Hetzner, DigitalOcean, Linode, AWS, Azure und GCP lassen sich aus AspireUI heraus anlegen.
  • AccountsKontenTwelve permissions rather than an admin flag, TOTP two-factor, sign-in through any OpenID Connect provider, and an activity log that records who did what. An API token can never do more than the person it belongs to.Zwölf Rechte statt eines Admin-Flags, TOTP-Zweifaktor, Anmeldung über jeden OpenID-Connect-Provider und ein Aktivitätsprotokoll, das festhält, wer was getan hat. Ein API-Token kann nie mehr als die Person, zu der er gehört.
  • Off-siteAuswärtsEvery backup can be copied to an S3-compatible bucket, a WebDAV share, or a directory on another machine over scp. The whole instance exports to one archive and imports into the next one.Jedes Backup kann in einen S3-kompatiblen Bucket, auf eine WebDAV-Freigabe oder per scp in ein Verzeichnis auf einer anderen Maschine kopiert werden. Die ganze Instanz exportiert in ein Archiv und importiert in die nächste.
  • umbrel store
  • unraid template
  • casaos
  • MCP server
  • webhook updates
  • nginx proxy manager
  • seed file
04

Or ignore Aspire entirely

Oder Aspire komplett ignorieren

None of the three sections above has to interest you. Put AspireUI on a machine in your own network and use it the way people use Umbrel or Cosmos Server: open the store, pick one of 167 preconfigured apps, install it, get a URL. No canvas, no C#, no Aspire knowledge — the two shots at the bottom of this section are the entire workflow, taken from a live instance.

Keiner der drei Abschnitte darüber muss einen interessieren. AspireUI auf eine Maschine im eigenen Netz stellen und so benutzen, wie andere Umbrel oder Cosmos Server benutzen: Store öffnen, eine von 167 vorkonfigurierten Apps aussuchen, installieren, URL bekommen. Kein Canvas, kein C#, keine Aspire-Kenntnisse — die zwei Bilder am Ende dieses Abschnitts sind der ganze Arbeitsablauf, aufgenommen auf einer laufenden Instanz.

The difference is underneath. Every installed app is an ordinary Aspire stack and an ordinary Compose file, so nothing ends up in a format only this tool can read — and on the day you do want to look, you open it and everything is there.

Der Unterschied liegt darunter. Jede installierte App ist ein gewöhnlicher Aspire-Stack und eine gewöhnliche Compose-Datei; nichts landet in einem Format, das nur dieses Werkzeug lesen kann — und an dem Tag, an dem man doch hineinsehen will, ist alles da.

A Proxmox host is the shortest way there. One script goes from nothing to a working URL: it creates a clean Debian VM, installs Docker, starts AspireUI with the socket mounted, and prints the address.

Ein Proxmox-Host ist der kürzeste Weg dahin. Ein Skript führt von nichts zu einer funktionierenden URL: Es erstellt eine frische Debian-VM, installiert Docker, startet AspireUI mit eingebundenem Socket und gibt die Adresse aus.

A VM, not an LXC container. Hosting starts other containers through the Docker socket, which needs real Docker: straightforward in a VM, fiddly with Docker-in-LXC on PVE. It also keeps a root-equivalent socket inside one disposable place — the honest reason for the extra VM, not a preference. Tear it all down again with qm stop <vmid> && qm destroy <vmid>.

Eine VM, kein LXC-Container. Hosting startet andere Container über den Docker-Socket, und das braucht echtes Docker: in einer VM unkompliziert, Docker-in-LXC auf PVE fummelig. Außerdem bleibt so ein root-äquivalenter Socket an einem wegwerfbaren Ort — der ehrliche Grund für die zusätzliche VM, keine Geschmacksfrage. Alles wieder weg mit qm stop <vmid> && qm destroy <vmid>.

browser *.acme.dev A → PVE HOST nginx proxy manager :443 · TLS DEBIAN VM · DOCKER aspireui :8080 · DOCKER SOCKET wordpress :32768 gitea :32769 volumes + backups S3 · WEBDAV · SCP

A real domain per app. Put Nginx Proxy Manager in front once, and AspireUI drives that same instance from Settings → Hosting: a hosted app is given a hostname and a Let's Encrypt certificate from its own menu, without a second admin UI in the loop. Set the public host once and every app URL is built from it.

Eine echte Domain pro App. Einmal Nginx Proxy Manager davor, und AspireUI steuert genau diese Instanz aus Settings → Hosting: Eine gehostete App bekommt Hostname und Let's-Encrypt-Zertifikat aus ihrem eigenen Menü, ohne Umweg über eine zweite Admin-Oberfläche. Den Public Host einmal setzen, und jede App-URL wird daraus gebaut.

Proxmox snapshots cover the VM. The scheduled volume backups cover the app data, with a copy of each going to S3, WebDAV or another machine over scp. The two are not substitutes for one another.

Proxmox-Snapshots sichern die VM. Die geplanten Volume-Backups sichern die App-Daten, und von jedem geht eine Kopie nach S3, auf WebDAV oder per scp auf eine andere Maschine. Das eine ersetzt das andere nicht.

Nothing here is Proxmox-specific. A NAS, a spare mini PC, a VPS or an existing Docker host work the same way, and this repository doubles as an Umbrel community store and an Unraid template if that is where you already live.

Nichts davon ist Proxmox-spezifisch. Ein NAS, ein übriger Mini-PC, ein VPS oder ein bestehender Docker-Host funktionieren genauso, und dieses Repository ist zugleich ein Umbrel-Community-Store und ein Unraid-Template, falls man dort schon zu Hause ist.

# on the Proxmox host, as root
curl -fsSLO https://raw.githubusercontent.com/fgilde/AspireUI/master/deploy/pve-install-aspireui.sh
IP=192.168.1.50/24 GW=192.168.1.1 RAM=8192 CORES=4 bash pve-install-aspireui.sh

Your own projects come from a repository. Paste a git URL: if it holds a docker-compose.yml, an aspireui-app.json or an Aspire AppHost, AspireUI builds it and deploys it as a hosted app — branch, compose file, services and environment are picked in the dialog. Pull and redeploy later from the app's own menu, or let a webhook do it when the repository or the image moves.

Eigene Projekte kommen aus einem Repository. Eine Git-URL einsetzen: Enthält sie eine docker-compose.yml, eine aspireui-app.json oder einen Aspire-AppHost, baut AspireUI sie und deployt sie als gehostete App — Branch, Compose-Datei, Services und Umgebung wählt man im Dialog. Später aus dem Menü der App neu ziehen und deployen, oder einen Webhook das tun lassen, wenn sich Repository oder Image bewegt.

A live AspireUI instance with two stacks and seven hosted apps
A live instance — two stacks, seven hosted apps, each reachable on its own domain
Eine laufende Instanz — zwei Stacks, sieben gehostete Apps, jede über ihre eigene Domain erreichbar
The AspireUI app store, apps grouped by category
The store — apps by category, install in one click, secrets generated per install
Der Store — Apps nach Kategorie, Installation mit einem Klick, Secrets pro Installation neu erzeugt
05

If the AppHost already exists

Wenn der AppHost schon existiert

Then AspireUI can be part of it. Nextended.Aspire.Hosting.AspireUI adds it as a resource — the container, an HTTP endpoint, the host Docker socket, a named volume for its data — and then writes down the entire first run: the admin account, further accounts with a permission preset, deploy targets, catalog apps, a starter stack built from the ProjectResources in this very AppHost, the assistant pointed at an Ollama container in the same stack, single sign-on, off-site backups.

Dann kann AspireUI ein Teil davon sein. Nextended.Aspire.Hosting.AspireUI fügt es als Ressource hinzu — Container, HTTP-Endpunkt, Docker-Socket des Hosts, ein benanntes Volume für die Daten — und schreibt dann den ganzen ersten Start auf: das Admin-Konto, weitere Konten mit Rechte-Preset, Deploy-Ziele, Katalog-Apps, einen Start-Stack aus den ProjectResources genau dieses AppHosts, den Assistenten auf einen Ollama-Container im selben Stack gezeigt, Single Sign-on, Backups nach auswärts.

Everything is idempotent by name. Restarting with the same AppHost changes nothing, adding one entry adds exactly that one, and anything somebody changed in the UI stays changed unless you explicitly ask for the opposite. Secrets come from Aspire parameters, so they stay out of the source and out of the manifest.

Alles ist idempotent über den Namen. Ein Neustart mit demselben AppHost ändert nichts, ein zusätzlicher Eintrag fügt genau diesen einen hinzu, und was jemand in der Oberfläche geändert hat, bleibt geändert — es sei denn, man verlangt ausdrücklich das Gegenteil. Secrets kommen aus Aspire-Parametern und bleiben damit außerhalb von Quellcode und Manifest.

Docs for the package: English · Deutsch · runnable sample. Seeding without the package is environment variables and a seed file.

Doku zum Paket: Deutsch · English · lauffähiges Beispiel. Ohne das Paket geht dasselbe über Umgebungsvariablen und eine Seed-Datei.

dotnet add package Nextended.Aspire.Hosting.AspireUI
AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);

var api    = builder.AddProject<Projects.Api>("api");
var web    = builder.AddProject<Projects.Web>("web").WithReference(api);
var ollama = builder.AddOllama("ollama").WithDataVolume();

builder.AddAspireUI()
    .WithAdminUser("admin", builder.AddParameter("admin-password", secret: true))
    .WithProjectStack("My App", api, web)   // canvas + sources mounted
    .WithApps("gitea", "vaultwarden")
    .WithOllamaAssistant(ollama, "llama3.2")
    .WithSingleSignOn("https://id.example.com/realms/main", "aspireui",
                      builder.AddParameter("sso-secret", secret: true))
    .WithSettings(s =>
    {
        s.PublicHost          = "apps.example.com";
        s.BackupIntervalHours = 12;
    })
    .WithAutoDeploy();

builder.Build().Run();

// AddOllama comes from the Aspire Community Toolkit

// AddOllama kommt aus dem Aspire Community Toolkit

06

A decent way to learn Aspire

Eine brauchbare Art, Aspire zu lernen

The reason is mechanical, not motivational: the code appears the moment you make the call. Drop a Postgres node and there is the AddPostgres("db").WithDataVolume(); wire a project to it and the WithReference(db) lands in the right place in the right chain. Delete it again and watch what disappears with it.

Der Grund ist mechanisch, nicht motivierend: Der Code erscheint in dem Moment, in dem man den Aufruf macht. Einen Postgres-Knoten ablegen — da steht AddPostgres("db").WithDataVolume(); ein Projekt daran hängen, und WithReference(db) landet an der richtigen Stelle in der richtigen Kette. Wieder löschen und zusehen, was mit verschwindet.

Then the other direction: import an existing AppHost and read it as a graph. Publish one and put the generated Compose file, Helm chart or Bicep next to the C# that produced it. And the store apps are ordinary stacks — open one and see how its volumes, published ports and companion database were actually wired.

Dann die andere Richtung: Einen bestehenden AppHost importieren und als Graph lesen. Einen veröffentlichen und die erzeugte Compose-Datei, das Helm-Chart oder das Bicep neben den C#-Code legen, der sie erzeugt hat. Und die Store-Apps sind gewöhnliche Stacks — einen öffnen und sehen, wie Volumes, veröffentlichte Ports und Begleit-Datenbank wirklich verdrahtet sind.

  • ctrl/⌘+K palette
  • undo/redo
  • dockable panels
  • themes
  • saveable layouts
  • roslyn intellisense
The add-resource dialog, generated from the installed Aspire integrations
Add-resource dialog — parameters, capabilities and a live C# preview
Ressourcen-Dialog — Parameter, Fähigkeiten und eine lebende C#-Vorschau
07

Documentation

Dokumentation

Getting startedErste Schritte Install it, open it, build the first stack. Installieren, öffnen, den ersten Stack bauen. Building stacksStacks bauen Canvas, catalog, property grid, code round-trip. Canvas, Katalog, Property-Grid, Code-Rundreise. Running & deployingStarten & deployen Run, dashboard, publish to Compose, Helm, Bicep. Run, Dashboard, Publish zu Compose, Helm, Bicep. Hosting Appliances with a URL: limits, health, backups, shell. Appliances mit URL: Limits, Health, Backups, Shell. Deploy targetsDeploy-Ziele SSH, TCP+mTLS, Kubernetes, ACA, Cloud Run, ECS. SSH, TCP+mTLS, Kubernetes, ACA, Cloud Run, ECS. App catalogApp-Katalog All 167 apps, and how to submit your own. Alle 167 Apps — und wie man eine eigene einreicht. Users & permissionsNutzer & Rechte Twelve permissions, two-factor, OIDC, activity log. Zwölf Rechte, Zweifaktor, OIDC, Aktivitätsprotokoll. The assistant chatDer Assistenz-Chat Sessions, tools, and why it can only do what you can. Sessions, Tools — und warum er nur kann, was du kannst. Seeding an installInstallation vorbelegen Accounts, targets, apps and settings, written down. Konten, Ziele, Apps und Settings, aufgeschrieben. Export & importExport & Import Move an instance, or hand over a support bundle. Eine Instanz umziehen oder ein Support-Bundle abgeben. Umbrel & UnraidUmbrel & Unraid This repo is also a community store and a CA template. Dieses Repo ist auch Community-Store und CA-Template. All pagesAlle Seiten Seventeen pages with search. Siebzehn Seiten mit Suche.
08

Get in touch

Kontakt & Unterstützung

A question, a bug, an app you want in the store — write, it arrives. And if AspireUI saves you an afternoon now and then, there is a way to say so.

Eine Frage, ein Fehler, eine App, die in den Store soll — schreib, es kommt an. Und wenn dir AspireUI ab und zu einen Nachmittag spart, gibt es einen Weg, das zu sagen.