Most visitors need the desktop or Android app, not the server, and the top Download button handed them the server zip straight away. It now scrolls to the download section, where the app is listed first with the primary button and the server sits last, labelled as only for whoever hosts one.
The logo and name lead the page with the tagline as a small bold title above the lead. Screenshots are stored at full resolution, the gallery has a nav link and steps through every screenshot with the arrow keys or on-screen arrows, the phone shot moves beside the Security and privacy list, a community channel shot sits under the feature list, features get real bullets, and the wording moves backups to Extras and mentions theme effects.
The hero shows the current default theme, the green shot is a high-resolution CRT capture, and the grey login gives way to a chat channel in the Braid theme. The screen share and red login shots stay.
The project paragraphs join the About section beside the phone screenshot, which also evens out the column heights. Every screenshot opens full size on click or Enter, and closes on click or Escape. The captions under the screenshots are gone except the phone one.
Rebuilt from scratch: a short, documentation-style page with the start-up banner and a real screenshot up top, plain copy, a features list, the comparison table, setup steps, an honest security section with a table of every outside service the server contacts, numbers that refresh from GitHub, downloads, and a gallery. No tracking tag. The previous page is tagged old-homepage in git.
4.5.0 taught the server to make its certificate itself, but Start Haven.bat, Install Haven.ps1 and the web installer still went looking for openssl.exe first and reported a skipped certificate as done. They now call the same generator through scripts/gen-cert.js, the certificate carries the CA and server-auth flags phones expect when you import it, and the guide and support page stop telling people to install OpenSSL. Reported by MutantRabbit767.
The webhook ran the multipart parser before looking the token up, so a post
to a made-up token still cost up to 512KB of buffering. The token is now
resolved first and the body is only read for a real one.
The open profile card re-rendered its status and activity slots on every
online-users broadcast, which fires for every join, leave and poll, so a card
showing cover art recreated its image and restarted the progress timer each
time. It now compares against what it last rendered and only writes on a
change.
The API reference moves from the repo root to docs/listening-api.md next to
the other guides, and the links in Settings follow it.
The README had grown into a second copy of GUIDE.md, and the duplicated half
had gone stale while the guide stayed correct. It is now a front page: what
Haven is, how to start it, what you get, and a link to the guide for the rest.
Everything cut has been moved into GUIDE.md rather than dropped, including the
Tailscale walkthrough, slash commands, keyboard shortcuts, admin and moderation,
backups, GIF setup, translations, the full configuration table, and running
more than one server.
Corrections along the way:
- The Android app is Haven, not Amni-Haven. It was renamed to stop the confusion.
- Haven Desktop is no longer labelled beta, and the site's download card said
1.4.15 while the buttons above it already linked 1.4.28.
- The licence badge claimed MIT-NC. Haven is AGPL-3.0, which the comparison
table and the licence section both already said.
- The port forwarding section claimed Haven has no rate limiting. It has had
it for a long time, 20 attempts per 15 minutes per address, so the warning
was arguing people out of a protection they already have.
- The GIPHY signup walkthrough led nowhere, since GIPHY stopped issuing keys
to new servers. Tenor is the default and the steps now say so.
- File uploads are 25 MB by default and admin-configurable, not a flat 25 MB
and not the 1.5 GB the site claimed.
- No macOS build of the desktop app exists, so the FAQ no longer offers one.
The pages also missed a lot that has shipped: Ferry, single sign-on, the
in-app updater, backups, threads, bots and webhooks, push notifications,
stickers, personas, polls, guests, invite links, plugins, automod, the audit
log, and the fact that Haven Desktop can host a server by itself.
Discord import and the Ferry bridge are now presented together, since the
people who want one usually want the other.
Bumps the version, adds the CHANGELOG entry, and updates the download links
and version history on both site files.
The major number reflects the size of the release rather than a break in
compatibility. There are no migration steps: the schema changes only add, and
Ferry ships switched off. The notes say plainly that it touches shared code and
that Ferry has not been through a real deployment, and recommend a backup
first, because promising that nothing breaks is not something this release has
earned yet.
The screenshots were the main thing. Every shot on the page is cropped to
fit its frame (the hero uses object-fit: cover), so there was no way to
actually see one. They now open full size on click, tap or Enter, with the
alt text as a caption, and close on Escape, the button or the backdrop.
The hero needed pointer-events on top of that: all six frames are stacked
in one place and faded between, so the invisible top frame was swallowing
every click. The carousel also holds while the viewer is open, so closing
it returns you to the frame you picked rather than whatever rotated in.
Removed 235 em and en dashes. Most were the separator in version history
rows, where the version chip already separates itself. The rest became
commas, full stops, colons or parentheses depending on what the sentence
was doing. The one in the comparison table meant "not applicable" and now
says so.
The Discord import and Haven Desktop banners no longer say NEW. Both have
been in for a long time. The import blurb also claimed "Haven v2.0 can
import your entire server", which has been wrong for a year and a half of
releases; it now says Haven, with no version to go stale again.
Both copies stay byte-identical, BOM intact.
Covers everything since v3.47.0, including the eight commits that were
pushed after that tag and never released: the invite buttons, the upload
cancel button, unban for moderators who can ban, the sub-channel nesting
permission fix, the Braid Layout fixes, and the group DM encryption design.
* Design: end-to-end encrypted group DMs
Group DMs do not exist yet — start-dm takes a single targetUserId — so this
is a greenfield design rather than a retrofit.
Proposes an epoch group key: one random AES-256 key per group per epoch,
wrapped to each member over the pairwise ECDH channel that already exists,
rotated on every membership change. Messages and attachments are encrypted
once regardless of group size.
Records two properties of the current 1:1 scheme that the design turns on,
both of which are easy to miss: there is no forward secrecy, and there is no
cryptographic sender authentication — the pairwise key is symmetric, so
either party can already produce a ciphertext the other accepts, and sender
identity is a server assertion. The chosen scheme therefore widens the set
who could forge from one to N-1 rather than introducing a new weakness, and
the doc says so rather than glossing it.
Rejects pairwise fan-out (multiplies every message and attachment by member
count), sender keys (do not authenticate without a signing key Haven lacks),
and MLS (no vetted stack across JS, Kotlin and Swift; disproportionate for
3-10 person groups).
Notes the upgrade path in dependency order, starting with an ECDSA signing
key that would close the same authentication gap 1:1 DMs already have.
* Group DM E2E: sign messages rather than settling for a shared-key trade
Revises the design to do sender authentication properly instead of noting
the gap and moving on.
Adds an ECDSA P-256 signing identity key as the foundation: wrapped in the
same password-derived blob, published through the same TOFU-pinned flow.
Every message is signed over a digest binding channel, epoch, sender and
ciphertext, so a valid ciphertext cannot be replayed into another group or
epoch, or re-attributed. Confidentiality comes from the epoch key and
authenticity from the signature, which is what makes one shared group key
safe: everyone can decrypt, only a key holder can author.
Applies the same signature to 1:1 DMs, which have the identical forge gap
today.
P-256 over Ed25519 for reach only — WebCrypto, JCA and CryptoKit all cover
it with no polyfill, and this has to work identically across three
independent client implementations.
Documents why a per-message ratchet is the wrong answer here despite being
the textbook one. Haven decrypts history on demand from server-held
ciphertext on every scroll-back, so deleting old message keys would make
re-fetched history undecryptable. A ratchet buys forward secrecy only by
breaking scrollback, or by persisting every message key forever — more key
material at rest than the single epoch key it replaces. Forward secrecy is
therefore epoch-granular with rotation policy as the knob.
Also records that key presence is effectively universal (publish-public-key
fires on every init) while key availability is not, since a fresh device
without a password lands in the existing ghost state. Only the recovery
path needs to care.
* Group DM E2E: detect a tampered channel by verifying the conversation
Adds transcript chaining and roster gossip, and records why network
identifiers were rejected for the same job.
Each message carries prev, the hash of the previous envelope its sender had
seen, inside the signed digest. Signatures alone authenticate each message
but say nothing about the set of them, so a hostile server can still drop,
withhold or reorder and every remaining signature still verifies. Chaining
turns the history into an append-only structure the server cannot rewrite:
a withheld message leaves the next prev dangling, reordering fails to link,
and a split view makes two members' chains diverge. Concurrent sends share
a prev legitimately, so clients treat it as a DAG and alarm only on a prev
that never arrives.
Roster gossip has each member publish a signed digest over the sorted group
key list. Matching digests mean nobody has been fed a substituted key;
a lone mismatch names the disagreement. A 1:1 conversation cannot do this
because there is no third party to disagree with — the group is its own
redundancy, so substitution becomes detectable without reading safety
numbers aloud. The existing pairwise safety number stays as the manual
escalation.
MAC and IP were considered for this and do not work: a browser cannot read
its own MAC, MAC does not survive the first router hop so it could only be
self-reported, self-reported values are attacker-controlled, a
server-observed IP is circular when the server is the untrusted party, both
are deliberately unstable now so they would emit false alerts that train
people to dismiss warnings, storing them is the tracking surface this
project avoids, and neither says anything about whether a fetched public
key is genuine.
* Point the constraint note at the tamper-detection section too
Rich presence shipped in 3.33.0 but was only ever mentioned in the
version history blurb, so nobody reading the README or the landing
page would know it exists.
- README: new Rich Presence row in the features table, plus a full
setup section covering all four sources and why Last.fm is the
recommended one
- Landing page: new Rich Presence feature card
- Note the GIF Favorites tab from 3.34.0, also undocumented
- Document PUBLIC_URL in the configuration table