Documents
phil/well-known-bundleHeaders
Every answer carries X-Robots-Tag: noindex: the documents are for software, not for search results. A successful
answer whose document sets no max-age and no no-store of its own is public with a max-age of cache_max_age
and carries a hash of its body as ETag; a request that holds it gets a 304. Errors and redirects keep Symfony's
private, no-cache. The routes are stateless and no document sets a cookie.
| Document | Media type | CORS |
|---|---|---|
security.txt | text/plain; charset=utf-8 | no |
change-password | a 302 | no |
webfinger | application/jrd+json | *, errors included |
nodeinfo | application/json | * |
| NodeInfo 2.1 | application/json; profile="http://nodeinfo.diaspora.software/ns/schema/2.1#" | * |
did.json | application/did+ld+json with an @context, else application/did+json | * |
did-configuration.json | application/json | * |
atproto-did | text/plain; charset=utf-8 | * |
apple-app-site-association | application/json | no |
assetlinks.json | application/json | no |
documents | content_type | cors |
security.txt
RFC 9116. The fields in the order of the RFC, one per line, Contact first, Expires in UTC, Preferred-Languages on
one line:
Contact: mailto:security@example.com
Expires: 2027-06-30T00:00:00Z
Preferred-Languages: fr, en
Canonical: https://example.com/.well-known/security.txt
The text is written when the container is built. RFC 9116 recommends an OpenPGP cleartext signature: the bundle holds
no key, and the application signs the text with the SecurityTxtSigner it names in security_txt.signer.
The expiry as a health check
With phil/monitoring-bundle installed, the bundle registers SecurityTxtExpiryCheck, the security_txt check of the
site's health, tagged phil_monitoring.health_check. It reads the Expires of the file on the clock service:
| Time left | Status | Summary |
|---|---|---|
More than security_txt.expiry_warning_days days | up | Expires on 2027-06-30T00:00:00+00:00. |
| That many days or fewer | degraded | The security.txt expires on 2027-06-30T00:00:00+00:00, in 12 days. |
| None | down | The security.txt expired on 2027-06-30T00:00:00+00:00. |
The days left are rounded up. A container kept running past the date thus fails the check, and the readiness of the site with it, instead of serving a file that has expired. Without phil/monitoring-bundle, no check is registered.
change-password
The W3C's well-known URL for changing passwords: a 302 to the route or URL of the configuration, so that password
managers send their users to the right page.
WebFinger
RFC 7033: see WebFinger.
NodeInfo
/.well-known/nodeinfo links to the 2.1 document by its absolute URL, generated by the router:
{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.1","href":"https://example.com/nodeinfo/2.1"}]}
The 2.1 document holds the version, the software, the protocols, the services, openRegistrations, the usage — the
counts the provider tells, none by default — and the metadata. The provider is asked on each request.
did.json and did-configuration.json
did.json is the DID document of the site's did:web identifier, as given. did-configuration.json follows the DIF
Well Known DID Configuration: its @context and linked_dids, the domain linkage credentials of the configuration in
their order, then those of the files. The bundle serves both as given and verifies no signature.
atproto-did
The AT Protocol proves a handle by its domain: the DID, as plain text without a line break. The configuration names
the site's own DID and the DID of other hosts; the host of the request picks it, in lowercase, else the site's; a host
with neither is a 404.
apple-app-site-association and assetlinks.json
Served at their exact address, without a redirect and as application/json, as iOS and Android require. The Android
statements are those of android_apps — relation and an android_app target —, then statements as given.
Fixed documents
Each entry of documents is served at its path with its media type, from a string or from a file read when the
container is built.