FeatherQuilld plugins
Extend FeatherQuilld with .NET plugins: plugin.yml, capabilities, routes, settings and the 162 events you can hook, generated from the Quilld SDK.
Last synced from FeatherQuilld 72bc34d on .
On this page
FeatherQuilld can load plugins written in .NET. A plugin can add HTTP routes to the daemon, run code before or after its own requests, and hook events such as a WebSpace starting or a backup being created. These are daemon plugins and are separate from FeatherPanel plugins.
Before you enable plugins
Plugins run inside the daemon, which runs as root. Turning them on is the same as giving every plugin author root on the node. That is why they are off by default. Only install plugins you have read or built yourself.
Enabling and installing
Set plugins.enabled: true, either in /etc/featherquilld/config.yml or in the web node's Advanced Config Overrides ({"plugins":{"enabled":true}}). The panel's Plugins Directory field setsplugins.directory. Restart the service after adding or changing plugins.
plugins:
enabled: true
directory: /var/lib/featherquilld/plugins
strict: false
disabled: []
settings:
hello:
greeting: Hi there- Each plugin goes in its own folder under the plugins directory, with its DLL and an optional
plugin.yml. disabledlists plugin IDs to skip.settings.<id>overrides the settings in the plugin's manifest.- With
strict: truea plugin that fails to load, verify or configure stops the daemon. Otherwise it is skipped with a warning.
A plugin is rejected when it has no ID, name or version, when its ID is already loaded, or whenMinHostVersion is newer than the running daemon. GET /api/system/plugins lists the loaded plugins and DELETE /api/system/plugins/<id> unloads one until the next restart.
Plugin structure
A plugin is a class library that references FeatherQuilld.Plugins and has one class implementingIPlugin. Configure(PluginContext) is called at startup. ImplementIPluginLifecycle as well to get StartAsync and StopAsync. The context gives youRoutes, Events, Logger, Settings, Services for dependency injection and Host for daemon information. This is the sample plugin from the repository, shortened:
public sealed class HelloPlugin : IPlugin, IPluginLifecycle
{
public PluginMetadata Metadata { get; } = new()
{
Id = "hello", Name = "Hello Plugin", Version = "0.3.0",
MinHostVersion = "0.1.0",
Capabilities = [PluginCapabilities.RoutesPublic, PluginCapabilities.WebSpacesRead],
};
public void Configure(PluginContext context)
{
context.Routes
.MapGet("/api/hello", (HttpContext _) => Results.Json(new
{
webspaces = context.Host?.WebSpaces.List().Count,
}))
.WithName("hello-greeting");
context.Events.On<WebSpacePowerBeforeEvent>(evt =>
{
context.Logger.LogInformation("Power {Action} for {Uuid}", evt.Action, evt.WebSpaceUuid);
return HookResult.Continue();
});
}
public Task StartAsync(CancellationToken ct = default) => Task.CompletedTask;
public Task StopAsync(CancellationToken ct = default) => Task.CompletedTask;
}Its plugin.yml. Values here override the metadata in code; main names the DLL when the folder has more than one.
id: hello
name: Hello Plugin
version: 0.3.0
description: Sample plugin demonstrating full SDK surfaces.
author: FeatherQuilld
main: FeatherQuilld.Plugins.Hello.dll
enabled: true
capabilities:
- routes.public
- routes.system
- host.info
- webspaces.read
settings:
greeting: Hello from plugin!Capabilities
A plugin declares what it needs. The daemon checks these today:
| Capability | Allows |
|---|---|
routes.public | Map routes outside /api/system |
routes.system | Map routes under /api/system |
host.info | Read the daemon version, UUID and uptime |
webspaces.read | List WebSpaces and read their name, runtime and status |
The SDK also defines these, which no host check uses yet:webspaces.write, dns.write, mail.write, ftp.admin, files.read.
Routes
context.Routes has MapGet, MapPost, MapPut, MapDeleteand MapPatch. Every plugin route needs the node token, like the rest of the Quilld API. A route under/api/system needs routes.system, any other route needs routes.public; without it the plugin is not configured.
Before(pattern, hook) and After(pattern, hook) run around matching requests, including the daemon's own routes. A before hook that returns HookResult.Cancel() stops the request.
Events
Subscribe with context.Events.On<TEvent>(handler) and return a HookResult. Most actions come as a pair: a …BeforeEvent and an …AfterEvent. From a before event,HookResult.Cancel() aborts the action (the API answers 403) and HookResult.Replace(value)skips it and uses your value as the result. After events can only observe. The list below is generated from the SDK:162 events in 17 groups.
Access
AccessDeauthorizeBeforeEvent, AccessDeauthorizeAfterEvent, AccessSetPermissionsBeforeEvent, AccessSetPermissionsAfterEvent
Auth
AuthValidateBeforeEvent, AuthValidateAfterEvent
Backup
BackupCreateBeforeEvent, BackupCreateAfterEvent, BackupRestoreBeforeEvent, BackupRestoreAfterEvent, BackupDeleteBeforeEvent, BackupDeleteAfterEvent, BackupImportBeforeEvent, BackupImportAfterEvent, BackupReconcileBeforeEvent, BackupReconcileAfterEvent
BuiltIn
PluginConfiguredEvent, ApplicationStartedEvent, ApplicationStoppingEvent, HttpRequestEvent, RouteExecutingEvent, RouteExecutedEvent, HealthCheckEvent
Dns
DnsZoneCreateBeforeEvent, DnsZoneCreateAfterEvent, DnsRecordCreateBeforeEvent, DnsRecordCreateAfterEvent, DnsRecordUpdateBeforeEvent, DnsRecordUpdateAfterEvent, DnsRecordDeleteBeforeEvent, DnsRecordDeleteAfterEvent, DnsUpsertABeforeEvent, DnsUpsertAAfterEvent, DnsTxtCreateBeforeEvent, DnsTxtCreateAfterEvent, DnsTxtDeleteBeforeEvent, DnsTxtDeleteAfterEvent
File
FileListBeforeEvent, FileListAfterEvent, FileReadBeforeEvent, FileReadAfterEvent, FileWriteBeforeEvent, FileWriteAfterEvent, FileCreateDirectoryBeforeEvent, FileCreateDirectoryAfterEvent, FileRenameBeforeEvent, FileRenameAfterEvent, FileCopyBeforeEvent, FileCopyAfterEvent, FileDeleteBeforeEvent, FileDeleteAfterEvent, FileUploadBeforeEvent, FileUploadAfterEvent, FileCompressBeforeEvent, FileCompressAfterEvent, FileDecompressBeforeEvent, FileDecompressAfterEvent, FileChmodBeforeEvent, FileChmodAfterEvent, FilePullBeforeEvent, FilePullAfterEvent, FileSymlinkBeforeEvent, FileSymlinkAfterEvent, FileDownloadArchiveBeforeEvent, FileDownloadArchiveAfterEvent
Ftp
FtpAuthBeforeEvent, FtpAuthAfterEvent, FtpWriteBeforeEvent, FtpWriteAfterEvent, FtpDeleteBeforeEvent, FtpDeleteAfterEvent, FtpRenameBeforeEvent, FtpRenameAfterEvent, FtpMkdirBeforeEvent, FtpMkdirAfterEvent
MailDomainAddBeforeEvent, MailDomainAddAfterEvent, MailDomainRemoveBeforeEvent, MailDomainRemoveAfterEvent, MailProvisionBeforeEvent, MailProvisionAfterEvent, MailSpamFilterBeforeEvent, MailSpamFilterAfterEvent
Malware
MalwareScanBeforeEvent, MalwareScanAfterEvent
Package
PackageInstallBeforeEvent, PackageInstallAfterEvent, PackageRemoveBeforeEvent, PackageRemoveAfterEvent
Panel
PanelSyncBeforeEvent, PanelSyncAfterEvent
Proxy
ProxyRebuildBeforeEvent, ProxyRebuildAfterEvent, AcmeEnsureCertsBeforeEvent, AcmeEnsureCertsAfterEvent, AcmeIssueBeforeEvent, AcmeIssueAfterEvent, StaticFileSyncBeforeEvent, StaticFileSyncAfterEvent
Schedule
ScheduleExecuteBeforeEvent, ScheduleExecuteAfterEvent, ScheduleTaskExecuteBeforeEvent, ScheduleTaskExecuteAfterEvent
Sftp
SftpAuthBeforeEvent, SftpAuthAfterEvent, SftpSessionOpenBeforeEvent, SftpSessionOpenAfterEvent, SftpSessionCloseAfterEvent, SftpWriteBeforeEvent, SftpWriteAfterEvent, SftpMkdirBeforeEvent, SftpMkdirAfterEvent, SftpRmdirBeforeEvent, SftpRmdirAfterEvent, SftpRemoveBeforeEvent, SftpRemoveAfterEvent, SftpRenameBeforeEvent, SftpRenameAfterEvent, SftpSetstatBeforeEvent, SftpSetstatAfterEvent, SftpOpenBeforeEvent, SftpOpenAfterEvent, SftpReadBeforeEvent, SftpReadAfterEvent, SftpReaddirBeforeEvent, SftpReaddirAfterEvent, SftpStatBeforeEvent, SftpStatAfterEvent
Transfer
TransferOutgoingBeforeEvent, TransferOutgoingAfterEvent, TransferIncomingBeforeEvent, TransferIncomingAfterEvent
Trash
TrashRestoreBeforeEvent, TrashRestoreAfterEvent, TrashPurgeBeforeEvent, TrashPurgeAfterEvent
WebSpace
WebSpaceCreateBeforeEvent, WebSpaceCreateAfterEvent, WebSpaceSyncBeforeEvent, WebSpaceSyncAfterEvent, WebSpaceDeleteBeforeEvent, WebSpaceDeleteAfterEvent, WebSpaceReinstallBeforeEvent, WebSpaceReinstallAfterEvent, WebSpaceSslRenewBeforeEvent, WebSpaceSslRenewAfterEvent, WebSpacePowerBeforeEvent, WebSpacePowerAfterEvent, WebSpaceConsoleCommandBeforeEvent, WebSpaceConsoleCommandAfterEvent, WebSpaceExecBeforeEvent, WebSpaceExecAfterEvent, WebSpaceRedisBeforeEvent, WebSpaceRedisAfterEvent, WebSpaceAbortInstallBeforeEvent, WebSpaceAbortInstallAfterEvent, WebSpaceRecreateRuntimeBeforeEvent, WebSpaceRecreateRuntimeAfterEvent, WebSpaceSslUploadBeforeEvent, WebSpaceSslUploadAfterEvent, WebSpaceSslDeleteBeforeEvent, WebSpaceSslDeleteAfterEvent