Skip to content
Open
106 changes: 106 additions & 0 deletions APIDOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4689,6 +4689,110 @@ RESPONSE:
}
```

### List Community App Repository Apps

Lists apps available from all configured community (third-party) DNS App repositories. A repository is any HTTPS URL serving a JSON manifest in the same schema as the official DNS App Store (a JSON array of app entries, or a single app entry as a bare JSON object). Each configured repository is fetched independently; if a repository is unreachable, returns invalid JSON, or has an unsupported JSON shape, it is reported with an `error` and does not affect the other repositories' listings. See `CommunityAppRepositories.md` for the full manifest schema and a guide for app authors who want to publish one.

Apps installed from a community repository are covered by their own separate automatic update timer, controlled by the `dnsAppsEnableAutomaticUpdateCommunity` DNS setting (disabled by default) — the official DNS App Store's `dnsAppsEnableAutomaticUpdate` timer only checks the official store and has no effect on community apps. Updates for community apps can also be applied manually via `downloadAndUpdate` after calling this endpoint to check for a newer version.

URL:\
`http://localhost:5380/api/apps/repositories/list`

PERMISSIONS:\
Apps: View

HEADERS:
- Authorization: Bearer <token>

WHERE:
- `token`: The session token generated by the `login` or the `createToken` call.
- `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized.

RESPONSE:
```
{
"response": {
"repositories": [
{
"name": "Example Repository",
"url": "https://example.com/store.json"
},
{
"name": "Another Repository",
"url": "https://example.org/store.json",
"error": "Response status code does not indicate success: 404 (Not Found)."
}
],
"storeApps": [
{
"name": "Example Community App",
"description": "An example app served from a community repository.",
"version": "1.0.0",
"url": "https://example.com/apps/ExampleApp.zip",
"size": "12.3 KB",
"repository": "https://example.com/store.json",
"repositoryName": "Example Repository",
"installed": false
}
]
},
"status": "ok"
}
```

### Add App Repository

Adds a community (third-party) DNS App repository URL. The URL must serve a JSON manifest in the same schema as the official DNS App Store (an array of app entries, each with `name`, `description`, and `versions`).

URL:\
`http://localhost:5380/api/apps/repositories/add?name=Example%20Repository&url=https://example.com/store.json`

PERMISSIONS:\
Apps: Modify

HEADERS:
- Authorization: Bearer <token>

WHERE:
- `token`: The session token generated by the `login` or the `createToken` call.
- `name` (optional): A display name for the repository. When unspecified, the URL is used as the display name.
- `url`: The HTTPS URL of the DNS App repository's JSON manifest.
- `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized.

RESPONSE:
```
{
"response": {},
"status": "ok"
}
```

### Remove App Repository

Removes a previously added community (third-party) DNS App repository URL. This does not uninstall any apps already installed from that repository.

URL:\
`http://localhost:5380/api/apps/repositories/remove?url=https://example.com/store.json`

PERMISSIONS:\
Apps: Modify

HEADERS:
- Authorization: Bearer <token>

WHERE:
- `token`: The session token generated by the `login` or the `createToken` call.
- `url`: The HTTPS URL of the DNS App repository's JSON manifest.
- `node` (optional): The node domain name for which the this API call is intended. When unspecified, the current node is used. This parameter can be used only when Clustering is initialized.

RESPONSE:
```
{
"response": {},
"status": "ok"
}
```

### Download And Install App

Download an app zip file from given URL and installs it on the DNS Server.
Expand Down Expand Up @@ -5118,6 +5222,7 @@ RESPONSE:
"notifyAllowedNetworks": [],
"dnsServerEnableCheckForUpdate": true,
"dnsAppsEnableAutomaticUpdate": true,
"dnsAppsEnableAutomaticUpdateCommunity": false,
"ipv6Mode": "Disabled",
"preferIPv6": false,
"enableUdpSocketPool": true,
Expand Down Expand Up @@ -5327,6 +5432,7 @@ WHERE:
- `notifyAllowedNetworks` (optional, cluster parameter): A comma separated list of IP addresses or network addresses that are allowed to Notify all secondary zones.
- `dnsServerEnableCheckForUpdate` (optional): Set to `true` to enable the DNS Server to check if an update is available when the Check For Update API is called which usually occurs after a user logs into the Web Console.
- `dnsAppsEnableAutomaticUpdate` (optional, cluster parameter): Set to `true` to allow DNS server to automatically update the DNS Apps from the DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled.
- `dnsAppsEnableAutomaticUpdateCommunity` (optional, cluster parameter): Set to `true` to allow the DNS server to automatically update apps installed from Community (third-party) DNS App repositories. Independent of `dnsAppsEnableAutomaticUpdate`, which only covers the official DNS App Store. The DNS Server will check for updates every 24 hrs when this option is enabled. Initial value is `false`.
- `ipv6Mode` (optional): Valid options are `Disabled`, `Enabled`, and `Preferred`. Initial value is `Disabled`.
- `enableUdpSocketPool` (optional): Set this to `true` to enable UDP socket pool. The DNS Server will use UDP socket pool for all outbound DNS-over-UDP requests when enabled.
- `socketPoolExcludedPorts` (optional): A comma separated list of port numbers that must be excluded from being used by the UDP socket pool.
Expand Down
84 changes: 84 additions & 0 deletions CommunityAppRepositories.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Community DNS App Repositories

DNS Server admins can add any HTTPS URL as a "Community" DNS App repository from the Apps &rarr; Community tab, giving apps that aren't accepted into the official DNS App Store (for example because they need hardware/infrastructure the maintainer can't test against — see [issue #2058](https://github.com/TechnitiumSoftware/DnsServer/issues/2058)) a distribution path of their own.

This document covers both sides: admins who want to **install** someone else's community app, and authors who want to **publish** one. For the admin-facing API itself (`apps/repositories/add`, `apps/repositories/list`, `apps/repositories/remove`), see `APIDOCS.md`.

## Installing someone else's community app

There's no central index or directory of community repositories — this is a decentralized, ad-hoc distribution model, not a curated store like the official DNS App Store. To install an app someone else published:

1. Get the repository's manifest URL directly from the app author — their project's README, GitHub repo, an issue/PR discussion, or wherever they've shared it (Technitium community forums/Discord/Reddit, etc.).
2. In the DNS Server web console, go to Apps &rarr; Community, and add that URL as a repository (give it any display name you like).
3. If the app has a version compatible with your server, it shows up in the Community tab's app list with an Install button.

Since nothing here is vetted or reviewed, only add repository URLs from authors/sources you trust — an installed app runs as native code inside the DNS server process. See "No checksum or signature verification" below.

By default, community apps are **not** auto-updated, unlike apps from the official DNS App Store. To have the server check daily and automatically download/install newer versions for community apps too, enable "Enable Automatic Update For Community Apps" in Settings &rarr; General &rarr; Software Update — this is a separate switch from the official store's "Enable Automatic Update", so turning one off does not affect the other.

## Publishing your own community app

The rest of this document is for **app authors** who want their app installable this way.

### What you need to host

A repository is just a static JSON file served over HTTPS — a GitHub raw URL, a GitHub Pages page, a gist, anything that returns the right JSON. There's no submission process and no approval; the admin who wants your app pastes your manifest URL into their server.

The manifest is the exact same schema the official DNS App Store uses: either a JSON array of app entries, or a single app entry as a bare JSON object (useful if your repo only ever serves one app).

```json
[
{
"name": "Example Community App",
"description": "One-line description shown in the Community tab's app list.",
"versions": [
{
"serverVersion": "15.0",
"version": "1.0.0",
"url": "https://github.com/you/your-app/releases/download/v1.0.0/YourApp-1.0.0.zip",
"size": "12.3 KB"
},
{
"serverVersion": "15.4",
"version": "1.1.0",
"url": "https://github.com/you/your-app/releases/download/v1.1.0/YourApp-1.1.0.zip",
"size": "13.1 KB"
}
]
},
{
"name": "Another Community App",
"description": "A second, unrelated app served from the same repository.",
"versions": [
{
"serverVersion": "15.0",
"version": "2.3.0",
"url": "https://github.com/someone-else/another-app/releases/download/v2.3.0/AnotherApp-2.3.0.zip",
"size": "8.7 KB"
}
]
}
]
```

A single repository can serve as many app entries as you like — one repo isn't limited to one app. Each entry is looked up and resolved independently by `name`, so unrelated apps (even from different authors) can share one manifest URL.

Field notes:

- **`name`** must exactly match the app name your app registers with the DNS Server (the name shown in the Installed Apps list). The server uses this string as the install/uninstall/update key — a mismatch means "installed" detection and updates silently won't work.
- **`description`** is plain text (rendered HTML-encoded), shown in the Community tab.
- **`versions`** is a list, not a single object, even if you only ever publish one version. Each entry:
- **`serverVersion`**: the minimum DNS Server version this build requires.
- **`version`**: your app's version string.
- **`url`**: direct HTTPS download link to the `.zip` package (same package format as a manual/sideloaded app install — same as what you'd upload via Apps &rarr; Install from Zip).
- **`size`**: a human-readable size string (e.g. `"50.02 KB"`). It's display-only, not validated against the actual download.
- When resolving which version to offer, the server picks the entry with the **highest `serverVersion` that is still `<=` the running server's version**. This lets you publish multiple builds targeting different server compatibility ranges in one manifest, same as the official store does.
- Any entry the server can't parse (missing fields, bad JSON) is skipped without breaking the rest of your manifest or any other configured repository.

### No checksum or signature verification

Same trust model as the official store: the server fetches your `url` and installs whatever `.zip` is there over HTTPS. There is no checksum/signature check on the package. An admin adding your repository URL is trusting your HTTPS endpoint (and its release infrastructure) directly — say so in your own README if you use a mutable "latest" URL versus a pinned release tag.

### Writing the app itself

This repository's manifest format only covers *distribution*. For the actual app implementation (the interfaces to implement, how config/records/query logging hooks work), the `DnsServerCore.ApplicationCommon` project's interfaces (`IDnsApplication`, `IDnsQueryLogger`, `IDnsAuthoritativeRequestHandler`, `IDnsRequestBlockingHandler`, `IDnsAppRecordRequestHandler`, `IDnsPostProcessor`, etc.) are the contract, and the `Apps/` folder in this repository has working, real examples (e.g. `Apps/DnsBlockListApp`, `Apps/QueryLogsSqliteApp`) to copy patterns from.
Loading