Publishing

Share a page as a read-only copy at a public URL. Visitors need no account.

Publishing a page

Open a page and use the globe button in its header. Publishing takes a snapshot of the page as it is now. Later edits stay private until you republish; the button shows a dot while there are unpublished changes.

Only pages can be published. Folders, sections, archived pages and conflict copies cannot.

The published copy has the page's title, body and table of contents, in the workspace's theme and custom CSS at the time of publishing. You choose whether it also shows:

Republishing replaces the snapshot and keeps the URL, the toggles, the password and the expiry.

What stays private

Before publishing, a check lists links and embeds that will not work for visitors. Publishing with any of them needs a confirmation.

Password and expiry

A password puts a form in front of the page. A correct password unlocks it in that browser for 30 days. Changing the password signs every visitor out. After 10 tries in 5 minutes from one address, the form refuses more for a few minutes.

An expiry date takes the page offline at that time. Visitors then see "This page is no longer shared." Pages with a password or an expiry are not indexed by search engines.

Taking a page down

Unpublishing, moving a published page to the trash or deleting the workspace takes the public copy down. Each asks for confirmation first and lists the published pages that link to it. Visitors then get a 410 page. Restoring a page from the trash brings its publication back.

Slugs

Published pages live at https://is.underwhelm.ing/p/<slug>. The default slug is the title plus six random characters, such as weekly-review-k3f9q2.

Custom domains

Add a domain under Settings → Workspace → Custom domains. Settings shows two DNS records to create at your DNS provider:

TypeNameValue
CNAMEnotes.example.comis.underwhelm.ing
TXT_aquamarine.notes.example.comThe token Settings shows

For a domain without subdomain, use an A record pointing at the server's address instead of the CNAME. The domain is checked when it is added, then every 10 minutes for a day, then hourly for a week. Settings shows "Waiting for DNS", "Verified" or "Failed" with what was found, and "Check now" checks again at once. Only one workspace can verify a domain.

Once verified, pick the domain in a page's Publish panel. The page moves to https://<domain>/<slug> and its old address redirects there with a 301. The domain's root lists its published pages that have no password.

Removing a domain asks first and names the pages on it. They move back to /p/<slug>; links shared with the domain address stop working.

On a verified domain, /<slug> serves that domain's pages and / lists them. Removing a domain moves its pages back to the default domain under the same slugs, or a suffixed slug when one is taken.

TLS for custom domains

Self-hosted servers need a reverse proxy that gets certificates for custom domains on demand. The server answers GET /domains/tls_allowed?domain=<host> with 200 for verified domains and an error for anything else, which is the check Caddy's on-demand TLS expects:

{
  on_demand_tls {
    ask http://localhost:3000/domains/tls_allowed
  }
}

https:// {
  tls {
    on_demand
  }
  reverse_proxy localhost:3000
}

API

Publishing needs the publish:notes scope. See publication endpoints in the REST API and the notes_publish, notes_unpublish and notes_publication_get MCP tools.