-
Morphit v1.21.6
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 43smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m10smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 54smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 5m7smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 45smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h20m57smorphit-release / Build + publish release tarball (push) Successful in 38m16sreleased this
2026-10-12 16:57:02 +00:00 | 17 commits to main since this releaseMorphit v1.21.6
A Tor/I2P-only server whose new release is not reachable yet now says so plainly and offers a way
forward, instead of stopping with a red ✗. Chats can be scrolled back to the first message and exported
whole, every FAQ answer was checked against the code and rewritten, a branded site names itself in many
more places, and the stats page's RPC card shows each node's measured state the moment it opens.Upgrading:
sudo morphit-ops upgradeon every server. No database change. Like every change to the
upgrade, the new behaviour starts with the upgrade AFTER the one that installs it. Every instance must
run v1.21.1 or later before 2026-11-01 00:00 UTC.Zero-clearnet upgrades that have to wait
On 2026-10-10, morphitlat's upgrade to v1.21.5 stopped twice ("could not reach this node's own indexer
… no answer within 60s"); the third try, a minute later, went through. Nothing was wrong: its indexer reads
the chain over Tor and I2P, and one read can take longer than a minute.- It keeps asking. The signed release record is now asked for again, for up to 8 minutes, when no
answer comes in time — not only when the answer lacks the record. - It says what it is doing. One line on how a zero-clearnet upgrade works, then a spinner that names
the step (reading the signed record over Tor/I2P; searching the federation, which instance it is asking,
how many it has asked, how many had no copy) and counts the time. The long per-URL lines are gone. - When the release cannot be reached yet: what it searched and for how long, what each instance
answered (by its directory name: "does not have v1.21.6 yet", "did not answer in time", "could not be
reached"), and that nothing was changed. At a terminal it asks: 1 try again now, 2 keep trying by itself
for up to an hour, 5 minutes after each try (it still asks before installing), 3 stop for now and try
again once more trusted instances have upgraded. Unattended it explains and stops, nothing changed
(exit 5). - A record signed by another key, or any other fault, is still a plain fail-closed error — also when the
node it asks lists a second record or did not answer in time on an earlier try. - An instance that does not answer no longer holds up the others: the next one is asked as soon as any
one has answered (before, one silent instance could hold up every one after it for up to 20 minutes). - If the server was upgraded by another session while it waited, it says so and stops, nothing changed.
- The waits run on a steady clock, so a Tor-only box that corrects its clock mid-wait neither stretches
nor cuts them; "kept trying for" shows the time it really took. Instance names in other scripts
(Chinese, Hindi, Persian) are shown whole and fit the spinner line; anything that could steer the
terminal is removed from them.
The site
-
Chats: scroll back to the first message, and export all of it. Scrolling up in a conversation now
loads older messages, page by page, all the way to the first one. Before, only the newest 50 messages
between the two of you could be reread, and a discussion whose messages were all older than those 50
showed as empty; it now shows them. Export chat now puts every message the two of you ever exchanged
in the PDF, from every discussion, each run of messages headed by the order it is about ("Not about an
order" for the rest). It reads the whole history first and keeps trying for up to about two minutes if
the site is busy; if part of it still can't be read, nothing is saved and it says so. Nothing is saved
either if the session locks while the file is being made. Messages sent in the same block now show in
the order the chain recorded them (they could appear the other way round). Old payment and address
messages loaded by scrolling back never change the status of a trade. -
Run a node → "Your relay account pays". Shorter lines, in every language: "Startup: 102 BLURT for
each new account your site creates (the chain's fee plus 2 BLURT to start)."; "10 BLURT + 10 Blurt
Power (BP) upon your user's first completed (paid) trade."; "BP rewards lent: 1 BP welcome stake and
loyalty-program rewards up to 1260 BP per user. You can retract it." The top-up line is unchanged. -
A branded site names itself in many more places. About 120 more strings now show the site's own
name instead of "Morphit" (about 150 more mentions in English, mirrored in all ten languages): the FAQ (21 questions
and the answers that speak about the site the visitor is using), the glossary, sign-up and the backup
card, the backup-keys page, the wallet and posting errors, the post form, the security page, settings,
page descriptions, the update notice, and the Blurt posts a user publishes ("I joined Vigilante
Trading", "Check out my offer on Vigilante Trading!"). Mentions of the software, the project, the
federation and other instances, releases and versions, the treasury and @morphit still say Morphit.
The degraded-mode page names the site too. -
Places that showed the address morphit.io on every site no longer do: the cheat sheet's "lost your
device" step, the Safari push-notification help, the phishing warning ("sites that look like this
one"), the QR-login warning and "the web app you see at morphit.io". The footer's Compare link said it
compares Morphit "to other options"; it compares this site's orderbook with another instance's, and
now says so. -
Homepage: the first-trades card. No "Your first trades" pill; the line under the heading reads "Pick
a cool username, that's it. Once it's registered on the chain, you can start trading anything,
instantly." Six numbered tiles, all in the brand tint and all floating gently: Get in, Post a buy (its
"(it's free)" only where this site pays the free first buy), Private chat, Welcome coins, Passive income
("…auto-pay you daily at N.NN% apr", the same staking rate and formula as the wallet, read through this
site's indexer; no rate is named until it arrives, or when the figure is not one a real chain gives) and
Loyalty rewards. A site without an operator tag
pays no rewards, so it shows four tiles (no welcome coins, no loyalty rewards). More room above and
below, so the glow no longer crowds the cards above or the coins below. The card, and its rate read,
load only when it scrolls near (a placeholder of the same height holds its place; without JavaScript
the placeholder takes no room). -
Primary buttons light up on hover. Every button with the solid brand face (the "Create your free
account" style, including the hand-built ones in the wallet, chat and modals) shows a 1px edge in the
brand accent on hover; disabled buttons do not. -
"BLURT" in capitals means the coin, and only the coin. The chain is "Blurt": "Blurt is Morphit's
coordination chain", "Morphit runs on Blurt, and listing fees are paid in its coin, BLURT", the
glossary entry ("Blurt (BLURT)": a blockchain and its coin), the BLURT payment-method and asset
descriptions ("the coin of Blurt, the chain … runs on"), and "Blurt Power" everywhere (it was written
"BLURT Power" in ten places per language). Every BLURT left is an amount, a balance, a price or a fee. -
Footer. The "Runs on Morphit" line under the footer logo is gone (it showed only on branded sites).
About this instance, linked in the footer, still shows which Morphit version a site runs. -
Six languages still said "on Morphit" in three older texts (the USDT and Dash privacy guides, the
Dogecoin asset note) where English names no site; they name the site now. -
FAQ search finds the introduction for "what is this", "what is this site", "what's this app" and
"what is this platform about" again, and on a branded site also for the site's name ("what is
Vigilante Trading"). In v1.21.5 it answered "what is this" with an unrelated entry (the iPhone one on
an unbranded site). On a branded site, a name made of everyday words no longer buries answers about
those words ("escrow" on a site called "Escrow Shop" finds the escrow answer), a name inside other
words is left alone ("Bit" in "Bitcoin"), and a search that names Morphit still finds its answer.
"where is the app" finds how to install it. -
Stats → RPC endpoints shows real measurements the moment the page opens, and keeps them fresh.
Before, the card first showed the relay pool's passive view (every hidden node "offline", clearnet
latencies from whenever they were last used), then about 20 seconds later the result of a fresh probe;
the refresh button repainted the passive view (mostly red) while it spun. Now the indexer measures
every published node itself, each one every 20 seconds (with one retry on a miss), and answers the
card instantly from those measurements. The card asks again every 10 seconds while it is visible and
when you come back to the tab, shows how long ago each node was measured ("measured 6s ago"), and never
replaces a newer answer with an older one. The refresh button asks the indexer for a fresh round
(at most once every 5 seconds; nodes are never probed twice at once) and keeps the current rows on
screen while it waits. A node not measured yet (just after the indexer starts) says "probing…", not
"offline"; a failed node shows its real reason (a node that stalls mid-answer now reads "timed out"); the
"reestablishing" label is gone. The card no longer waits for the page's other statistics to load first
(or vanishes when they fail), and those statistics keep their place while they load, so the card does
not jump. It counts "measured … ago" on the indexer's clock, and keeps working if either clock is off or
is corrected; without JavaScript the stats page shows no empty figures or "probing…".morphit-ops healthnow shows each node's latency (it showed "—" for every node), and a node the indexer has not
measured yet reads "being measured" instead of counting as unreachable. -
For API users:
/v1/chat/:a/:btakesorder=<permlink>to read one discussion (order=with no
value: the one about no order). Paging through/v1/chat/:a/:b,/v1/accounts/:account/feedbackand
/v1/accounts/:account/feedback-givencould skip rows recorded in the same block (they were sorted by
their id as text, "100" before "99", while the cursor compares numbers); every row now comes once. A
page far back in a chat history reads only that page. Each row of/v1/rpc-endpointsnow carries
checked_at, andcooldown_msis always 0./v1/statscounted a trade reviewed by both people twice; it counts it once now.
/v1/activity/volumeadded an order's volume once per review; it adds it once per order now.docs/API.md
documents/v1/rpc-endpointsand the reputation receipt, and no longer lists a/v1/accounts/:account
route the indexer never served. -
Every FAQ answer was checked against the code and rewritten to be short and plain. All 146
answers, in all ten languages, about 40% shorter overall (44% in English). A second, independent check
of every answer against the code followed, and its corrections are in too. Every number and claim was verified in the
code (fees, limits, timings, rewards, rate limits, menu labels); claims the code does not support were
removed or corrected, internals and history were cut, and cross-references now match the current
question titles. Answers now link to the pages they mention (My Orders, Run a node, the privacy
guides, the explorer…), and the three that showed "/privacy/{asset}" literally now link to the privacy
guides. "What's the most private way to sign in?" has a new title. Notable corrections: the no-JavaScript
answers (the FAQ answers, privacy guides, orderbook, profiles and reviews need JavaScript; pages like
security, glossary and run-a-node, the FAQ's questions and the RSS feeds do not), the welcome bonus (two
welcome rewards, how the free first buy fits in), hidden accounts (saved with your encrypted settings
while signed in, so they follow you; the hide button is on computers and tablets), the "New trader"
label (fewer than 4 completed trades), QR sign-in (the computer can't read chat messages), the chain's
smallest Blurt Power loan (about 33 BP), the chat export and rereading old messages (now everything
ever said, see above), the Monero TxID (also asked for when you tell a partner you paid in XMR), and when a
BTC/XMR price falls back to other sources. -
The same check found a few screens saying things the code does not do; they now match it: the
no-JavaScript notice (it said orders, profiles and reviews work without JavaScript), Settings →
Utility (signing out does wipe your keys from the device; Lock session keeps them), the hidden-accounts
note and hide button (the list follows you while signed in), the "New trader" screen-reader label, the
stranger-fee slow-down notice (blocks do not lower your standing), the QR-paired computer (chat
messages open only on the phone), the DAI network warning, the free first order's next steps (a review
can't cite the free order) and the review form ("free" → only Blurt's tiny network fee).
Smaller
- The snapshot mirror names only the addresses this server really has (clearnet, .onion, .b32.i2p).
- The staking rate shown on the wallet, the explorer and the homepage is left out when the chain data
behind it gives a rate no real chain state gives (20% or more); a lying RPC node could otherwise put any
rate there. - FAQ links that point to another site always open in a new tab and never pass the page along.
- The indexer reads at most as many RPC directory nodes as a valid signed directory can hold.
- A chat that reconnects to its live stream no longer misses messages sent in the same block as the last
one it had (the catch-up read sorted ids as text). The indexer also sorted block numbers as text in a
few places (operator registrations, BTC fee addresses, the upgrade reconcile); that would have gone
wrong from block 100,000,000. Fixed now.
About the v1.21.5 upgrade (no action)
- An upgrade to v1.21.5 run by v1.21.4 printed "⚠ Your instance origin could not be applied (… this build
is branded …)" and the same run then applied the origin anyway. v1.21.4's branding reset wrote back a
setting v1.21.5 no longer uses, so the fresh build looked branded for a moment. One-time: the self-heal
(run by v1.21.5) fixed it, and v1.21.5's own upgrades do not do it. A box upgraded straight from an
older release (timeapp) shows it once too, then the same fix.
Downloads
-
Source code (ZIP)
1 download
-
Source code (TAR.GZ)
3 downloads
- It keeps asking. The signed release record is now asked for again, for up to 8 minutes, when no
-
Morphit v1.21.5
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 41smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m11smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 51smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 4m31smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 46smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h29m38smorphit-release / Build + publish release tarball (push) Successful in 45m48sreleased this
2026-10-11 01:02:38 +00:00 | 18 commits to main since this releaseMorphit v1.21.5
A Tor/I2P-only server can now copy the federation snapshot from its peers over Tor/I2P, and a brand-new
one can fast-sync privately instead of replaying the whole chain. The site names only the coins its
operator accepts, the homepage invites visitors to make their first trades, the stats page's RPC card
shows each node's real state again, and the BETA marker is gone from the logo.Upgrading:
sudo morphit-ops upgradeon every server. No database change. morphit.io first: its
next anchored snapshot then names its .onion and .b32.i2p. Every instance must run v1.21.1 or later
before 2026-11-01 00:00 UTC, when the stricter consensus rules start.The federation snapshot over Tor/I2P
- The mirror asks the federation. v1.21.4's fallback looked for peers only in operator registrations
in @morphit's history. That history holds none (all 169 entries read on morphit.io, 2026-10-10), so on
morphitlat it asked nobody ("no federation peer's .onion or .b32.i2p address was found"). It now asks,
in order: the publisher's own addresses from the signed snapshot record, this server's federation
directory (the same list its upgrades use; the publisher's instance first), then any registration in
that history. A peer that does not hold the snapshot answers at once. - The snapshot record names the publisher's hidden addresses.
ops/pin-indexer-snapshot.shadds
hidden_mirrors(this server's .onion and .b32.i2p, as its indexer advertises them at/v1/instance)
to the indexer_snapshot_v1 record, under the same signature. A new server fast-syncs before it has an
indexer, so this is where it learns a private source. Servers that do not know the field ignore it
(checked against the v1.21.3 validator); a malformed one is dropped, and the publisher refuses to
sign one.
The site
- Homepage. The "Run your own Morphit site" card is replaced by a card that invites a visitor to sign
in and make a first few trades: three steps, and on a site whose relay pays them, the three rewards (a
free account, a free first buy, 10 BLURT + 10 Blurt Power after the first completed trade on a paid
listing). Its border light, glows and heading sheen move slowly, use only the theme's colours (so a
branded site re-tints it), and stop for visitors who ask for reduced motion. Someone who already has an
account on the device is sent to post or browse instead of to sign up. - Orderbook. The "What you get on Morphit" card is gone.
- Run a node. The "You automatically earn" and "Your relay account pays" boxes have the new wording
(the Startup cost per new account, Blurt Power (BP), retractable rewards, the rule of thumb). - Download. The Install, Source code & releases, Setup walkthrough and Join the federation cards are
gone. The intro says you can "install" an instance with an "app" icon or run your own node and be listed
in the Federation directory, with links. The Codeberg mirror says, in red, "Crypto projects banned".
"Morphit is 100% free and open source." - Stats → RPC endpoints. The card asks the indexer to ping every node, and the indexer answers only
once the slowest has answered or timed out — up to about 42 seconds when an I2P node is slow or down
(two tries of up to 20 seconds). The browser waited 8 seconds, gave up, and kept the pool's passive
snapshot: "Probing…" for the hidden nodes, which the pool seldom calls, and stale figures for clearnet
nodes it had not used lately. The browser now waits for the probe. (The reverse proxy's 60-second limit
for/v1/is longer than the indexer's worst case; a new smoke holds the three numbers together.) - Footer. The "Source" link under Resources is gone.
- licenses.txt. Now also lists Vite (its small lazy-loading helper is in every page's code; Vite's own
MIT licence only, not those of the build tools it bundles) and the Comfortaa font with its SIL OFL text,
and shows every source as a plain https link. - Security page. "Look at the Network tab in your browser." The zero-clearnet, chat and release cards
were checked against the code and rewritten:- Zero clearnet: the software refuses clearnet and a firewall lets only Tor and I2P out; package updates
and the clock go over Tor too; the node moves to Tor bridges by itself. Fee checks and prices travel
over Tor (not I2P). The claim is the node's own, made when its own checks pass. - Chat: the encryption (X25519 and ChaCha20-Poly1305) and sender proof as before, plus key pinning and
the 60-digit safety number; and plainly what is public — messages live on the Blurt chain, so who,
when, which order and each message's length are visible. - Releases: the git tag is GPG-signed on main; the record also anchors the offline bundle's hash; the
browser reads it from a public Blurt node and names any file that differs. - The directory's "Zero use of clearnet internet" badge now says, on hover, that it is the instance's
own claim.
- Zero clearnet: the software refuses clearnet and a firewall lets only Tor and I2P out; package updates
- Privacy & terms. "your chat conversations stay 100% private"; "a VPN, Tor, I2P, ENS or Lokinet";
the zero-clearnet paragraph corrected the same way (and "a marketplace node with no clearnet address to
block"). - About this instance. The "BTC fee key" row is gone: it showed a short key id a visitor could not
check against anything. (Which BTC address an order's fee goes to is still checked in the browser
against the key @morphit pinned on chain.) The file count is the number of files verify.json lists —
per site and per version — and the text now says exactly that. - The coins this site accepts. An operator who switches coins off (
MORPHIT_INDEXER_DISABLED_ASSETS)
now sees that everywhere the site names coins:- the homepage carousel (a network appears only while an accepted coin settles on it; barter only when
accepted; the two rows stay within one icon of each other); - the cheat sheet's asset list and the privacy guides' index;
- the FAQ: the entries about a switched-off coin are left out (and from "Related"), and the answers that
list the coins traded here ("What is Morphit?", "Where can I buy Blurt?", the welcome bonus, the
stablecoin warnings, privacy coins) list this site's coins and count them.
- the homepage carousel (a network appears only while an accepted coin settles on it; barter only when
- Plan. "Phase 7 — Cryptocurrency support", planned.
- Logo. The BETA marker is gone for good.
morphit-ops branding apply --betanow says so and stops;
aMORPHIT_INSTANCE_BETA_BADGEline left inmorphit.config.envis ignored.
Correction to the v1.21.4 notes
- They said the mirror asks "the publisher's own .onion and .b32.i2p (from its on-chain registration)".
@morphit has no such registration, so it asked nobody.
Documentation
- docs/SECURITY.md said the release job fails without the signing key. It publishes without
.ascfiles
then, and installed nodes accept the tarball only by its SHA-256 in @morphit's signed record. - docs/VERIFY-YOUR-DOWNLOAD.md named three git hosts; the source is mirrored to many.
Tests (maintainer)
- ops-cli tests can no longer reach the internet (test/setup/noInternet.ts), judged by the address a name
resolves to (CI's database is the containerpostgres). - The snapshot mirror's lookup of its own directory names itself (
user-agent), like every indexer fetch.
Downloads
-
Source code (ZIP)
2 downloads
-
Source code (TAR.GZ)
5 downloads
- The mirror asks the federation. v1.21.4's fallback looked for peers only in operator registrations
-
Morphit v1.21.4
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 56smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m41smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 47smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 4m37smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 45smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h20m40smorphit-release / Build + publish release tarball (push) Successful in 38m5sreleased this
2026-10-10 05:21:02 +00:00 | 19 commits to main since this releaseMorphit v1.21.4
A server on a network that filters Tor now moves its Tor onto bridges by itself, so its .onion stays
reachable. The twice-a-day release check, new in v1.21.3, works now: it could not run anywhere. An
upgrade no longer refuses a release because one node's history did not list its on-chain record yet.
A Tor/I2P-only server can now hold its own copy of the federation snapshot.Upgrading:
sudo morphit-ops upgradeon every server, Tor/I2P-only ones included. No database change.
This upgrade is run by the upgrade program of the release the server runs now. The repairs below run
from this release during the upgrade; the changes to how an upgrade reads the release record and to its
last lines take effect from the next upgrade. Every instance must run v1.21.1 or later before 2026-11-01 00:00 UTC, when the
stricter consensus rules start.Tor on a network that filters it
On 2026-10-09, morphitir's Tor loaded nothing:
- Its network sends every torproject.org name to a sinkhole (
10.10.34.36). - Connections to Tor relays open, but the circuits built over them stall.
- Plain Tor loaded 0 of 6 pages, and so did a fresh Tor client.
- The .onion could not publish its address record, so nobody could reach it over Tor.
Over the Tor Project's built-in bridges, Snowflake and obfs4, Tor connected at once. With those bridges
in/etc/tor/torrc, morphitir's .onion answered, from morphitir itself and from morphit.io.- The Tor bridges repair. It runs in the upgrade's background checks, and on a new timer
(morphit-tor-bridges.timer: half an hour after the timer starts, at boot or when the upgrade turns
it on, then every 6 hours). To run it now:sudo morphit-ops upgrade --tor-bridges.- It first checks that Tor works: this server's own .onion, then a page through Tor. A Tor that works
without bridges keeps its configuration. - When Tor loads nothing, it installs the transport programs from the distribution
(snowflake-client,obfs4proxy). - A Tor/I2P-only server uses obfs4 only: Snowflake needs DNS, which that server's egress rule refuses.
Its downloads go through Tor, so it installsobfs4proxywhile Tor still works. If its Tor loads
nothing before that, the result says how to bring the package in by hand. - It writes the bridges into
/etc/tor/torrcbetween# >>> morphit: Tor bridgesmarkers, only
aftertor --verify-configaccepts the file. The first original is kept as
/etc/tor/torrc.bak-before-bridges. The onion service's keys are not touched. - Tor restarts and must connect within 5 minutes; then the .onion or a page must load through it.
- A server already on bridges that loads nothing gets the release's bridges again, then plain Tor;
when plain Tor works, the bridges come out again. - A server on bridges that works is checked, at most once a day, with a separate, throwaway Tor client
without bridges, run as Tor's own user. It connects to public Tor relays, which a filtering network
can see. When it loads through plain Tor, the bridges come out, proven the same way. If this
server's Tor then does not work without them, they go back, proven, and plain Tor waits a week. - When nothing works, the previous
torrcgoes back and Tor restarts on it. If it cannot be written
back, the result says so. /etc/tor/torrcis read again before each write, by this repair and by the onion proof-of-work
repair. An edit made meanwhile, by an operator or another repair, is never overwritten or put back
over.- Each Snowflake bridge also names one domain front as
front=, the only form Ubuntu's
snowflake-clientreads. - The whole repair takes at most 45 minutes, and runs one at a time.
- The timer only runs with an upgrade program that knows
--tor-bridges. On a server moved back to an
older release it does nothing.
- It first checks that Tor works: this server's own .onion, then a page through Tor. A Tor that works
- The bridges ship with the release. A network that filters Tor blocks torproject.org too, so the
list Tor Browser uses is inops/tor/builtin-bridges.json. docs/OPERATIONS.md §51.0 says how to
refresh it. - The IPFS seed check tries a .onion three times. When it still fails, it says why (curl's own
message) and names the repair, instead of one try and "HTTP 000".
The release check
- It works now. In v1.21.3 it failed on every server with "morphit-indexer.service is not running"
while the indexer ran:- It runs as a throwaway user in a sandbox that cannot read
/etc/morphit/indexer.env. So it could
not tell a clearnet server from a Tor/I2P-only one, and took the strict path. - That path proves the answer on the indexer's address comes from the indexer service. To do so it
askedsystemctlfor the indexer's process ID, andsystemctlcannot reach systemd from that
sandbox ("Transport endpoint is not connected"). - It now reads the indexer's processes from its cgroup, which only systemd writes. The listener must
still belong to the indexer's user. Proven on morphitir's real unit.
- It runs as a throwaway user in a sandbox that cannot read
- A reason too long for its alert ends with "…", instead of breaking off mid-word; one that already
ends with a full stop no longer gets a second one.
Upgrades and the release record
- One node's answer no longer decides that a release has no record. On 2026-10-08 morphit.io's
upgrade read @morphit's history through one node that did not list the new record yet, and refused;
the same command a minute later worked.- The upgrade now asks this server's indexer, then each configured Blurt node directly (not on a
Tor/I2P-only server). - When a node answered without the record, or listed it without having its block yet, it asks again
for up to 3 minutes, under the spinner, before refusing. - The record's signature decides, so any node may be asked. On a clearnet server, a release signed
by a pinned key needs no record and never waits. - The wait ends on time: no node is asked once the 3 minutes are up.
- The upgrade now asks this server's indexer, then each configured Blurt node directly (not on a
- The last lines say "Every service restarted on it (checked)." whenever each restarted service,
the MCP server and the Matrix alert bot included, was seen to stay up on the new version. Before, any
unrelated warning, such as one from the IPFS seed check, dropped that sentence. It is left out when
one did not come back, or when no service was restarted.
The federation snapshot
- A Tor/I2P-only server can mirror the snapshot. The mirror only asked IPFS's own network. A
Tor/I2P-only server sees two or three IPFS peers, and they need not hold the snapshot, so morphitlat
never became a mirror.- When IPFS cannot fetch it, the mirror now asks the publisher's own .onion and .b32.i2p (from its
on-chain registration) for the snapshot as a CAR (/ipfs/<cid>?format=car), and imports it under
the same CID. - Only the snapshot's own CID is pinned from it, whatever the peer's CAR names as its root. A peer's
answer is read only up to 64 MB, and a redirect is never followed. - Fetching stops 18 minutes into the mirror's run, leaving the later steps their time within its 30
minutes. A server with only a few IPFS peers gives the swarm 3 minutes and leaves the rest to the
federation peers. - The check against the signed SHA-256 still decides whether it is kept.
- morphit.io answers
?format=carboth from its IPFS node and through its site (kubo 0.42.0).
- When IPFS cannot fetch it, the mirror now asks the publisher's own .onion and .b32.i2p (from its
Releases (maintainer)
- Block 4 waits until the nodes list the record. After the broadcast it waits up to 5 minutes
until the nodes list the transaction in @morphit's history, which is where upgrades look for it.
Start Block 5 when it prints "Block 5 can start". This is what protects servers still running an
older upgrade program, which believes the first node that answers. A node that listed it once counts
as listing it, even if it stops answering.- It asks the public nodes. A Tor/I2P-only server on an older upgrade program reads through its own
hidden nodes, which can list the record later: if its upgrade says there is no record, run it again
a few minutes later.
- It asks the public nodes. A Tor/I2P-only server on an older upgrade program reads through its own
Correction to the v1.21.3 notes
- They said "This upgrade is run by v1.21.2's upgrade program". Servers on v1.21.1, such as morphitir
and morphitlat, ran v1.21.1's.
Downloads
-
Source code (ZIP)
1 download
-
Source code (TAR.GZ)
6 downloads
- Its network sends every torproject.org name to a sinkhole (
-
Morphit v1.21.3
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 36smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m4smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 43smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 4m20smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 43smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h18m17smorphit-release / Build + publish release tarball (push) Successful in 36m32sreleased this
2026-10-09 01:50:56 +00:00 | 22 commits to main since this releaseMorphit v1.21.3
Every server now tells its operator when a newer release is out. The relay no longer restarts itself
over an abandoned node request. Blurt Power rewards that a node refuses now stop and say why. The site
now says plainly what operators earn and pay and what users get, and the first-trade bonus is no longer
lost to a reply.Upgrading:
sudo morphit-ops upgradeon every server, Tor/I2P-only ones included. No database change.
This upgrade is run by v1.21.2's upgrade program; the release check, the backup question's removal and
the after-restart wait below run from this release during the upgrade. Every instance must run
v1.21.1 or later before 2026-11-01 00:00 UTC, when the stricter consensus rules start. This release
adds one rule from that same time, about what uses up a user's first-trade bonus (below); instances that
have not upgraded by then still pay the bonus, by the old rule.Knowing a release is out
- The main menu reads @morphit's on-chain release record. Before, it asked only git.agorise.net and
gave it 2.5 seconds. When that host was slow, the menu showed "(couldn't check for updates — network)"
even though the record of the new release was already on chain, and an operator who opens the menu
now and then would read that as "nothing to do".- The menu now reads the record from this server's own indexer, on the server with no network. It
uses the answer only after checking that the process listening on that address is the indexer
service. - The record names exactly what an upgrade installs, so it decides.
- The code host is asked only when the record does not answer, never on a Tor/I2P-only server, and
once instead of twice. "Tor/I2P-only" is now decided the way the upgrade decides it; when that
cannot be told, the node is treated as Tor/I2P-only. - "Update available" appears only for a release newer than the installed one.
- It says "couldn't check" only when nothing answered.
- The menu now reads the record from this server's own indexer, on the server with no network. It
- The release check runs on every server, twice a day.
morphit-release-monitorshipped from v1.9
but nothing installed it. It sends an alert through the Matrix bot when Matrix alerts are set up.- Every install and every upgrade now puts it in place and turns its timer on.
- The upgrade also runs it once, reads what it logged, and says so if that run did not succeed,
with the command to look at it. - It runs every 12 hours (it was written for 6), as a throwaway user systemd makes for each run.
- It reads the record from this server's indexer. It asks the code host only when the indexer
answers but holds no record. - When it cannot check, its alert now gives the reason.
morphit-ops upgrade --check-onlyreads the on-chain record first on every server, and stops at
the first release source that answers.- A real upgrade says when the record names a newer release than the code host offers, for example
when git.agorise.net is blocked or has not published it yet, so the operator knows to run it again
later. - Requests to the code host get the time they are given. Node's own limit ended every connection
attempt after 10 seconds, whatever wait was set, so a slow code host failed a 30-second check after
20 seconds. The upgrade's release lookup and its download now use the wait they were given.
The relay and the indexer
-
The relay no longer restarts itself over a node request nobody waits for. On 2026-10-08 it
restarted twelve times with "unhandled_rejection", logged as "AbortError" or "TypeError: fetch failed".
The cause was a request to a second node that ended after the relay had already moved on, with nothing
catching its failure. Two things did that:- the node pool could still send its backup request after the first node had answered;
- a request cancelled before it started was left unwatched.
Both are fixed, in the indexer as well. Should such a request ever end unwatched again, the relay
logs it as a warning with its stack and keeps running. Any other unexpected error still stops it. -
A node answer the indexer cannot read no longer stalls its block reading. Before, it was left
unhandled, and the request waiting on it never finished. -
A database error while the relay settled a payment no longer gets it sent twice. It erased the
record of the signed transaction, so the next cycle signed and sent a new one. The record is now kept
and the payment is settled from the chain history; the failure is still counted, so a row that keeps
failing stops and reaches the operator. -
Blurt Power rewards (delegations) below the chain's minimum are held, not re-sent. Blurt accepts a
new delegation only of at least a third of its account fee (about 33.4 BP at today's 100 BLURT fee),
and a change to one only of at least a thirtieth (about 3.4 BP). The 1 BP welcome stake and the 10 BP
first loyalty reward are below that, so the chain refused them every time: on morphit.io two rewards
to one account were signed again about once a minute for five days, without the relay looking at the
chain, and the retry count never rose, so they never stopped or reached the operator.- The relay now reads the chain's limits and the current delegation before sending. A reward below
the minimum is held ("held: … below the chain's minimum delegation …" indrain-queue), checked
again every 6 hours, and lent once the account's rewards add up to it, usually at the 500 BLURT
milestone (61 BP). A target the chain already holds is marked done without a transaction. - A delegation is now looked up in the relay's account history, like a transfer.
- Only the newest reward for an account is sent. Each one carries the account's whole amount, so
an older one is retired as replaced. - A reward is never sent while an older one for that account may still land.
- Rewards waiting on each other no longer hold up the rest of the payout queue.
- What the nodes answered is kept, in the queue and in the log, so a refusal the chain repeats ends
the retries and shows its reason. - An older reward that has reached the retry limit no longer blocks newer ones for that account, and
an older one is retired only for a newer one that can still be sent.
- The relay now reads the chain's limits and the current delegation before sending. A reward below
-
morphit-ops drain-queueshows a delegation's amount in BP (it showed "0.00 BLURT"). It marks a
row that is waiting on the chain as waiting, and shows what the nodes answered in full.
Upgrades and the command line
-
The upgrade no longer asks about encrypting database backups.
-
The checks after the restart wait for the services to answer. systemd reports a service as
started before it listens, so the relay check could run against a relay that was not yet answering,
and warn.- The checks now wait up to 5 minutes in all for the services to answer on their health addresses,
and say which one did not. - The indexer is asked where its unit says it listens.
- The relay check's own wait is 30 seconds of time, not a count of tries.
- The checks now wait up to 5 minutes in all for the services to answer on their health addresses,
-
The braille spinner shows during the waits at the terminal, for example:
- the database commands (
status,signups,drain-queue, moderation and the like); doctor's configuration checks;fast-sync's stop and start;- the guided install's pre-flight and the silent stretches of the playbook;
- the unpack and each restart of an upgrade;
- the release check's run and retry;
- the service restarts that
edit,alt-addressandmcpoffer.
Its label is cut to fit the terminal; a longer one used to fill the screen with copies. Ctrl-C while
it turns gives the cursor back. The database commands no longer print the label into piped or
logged output, and under--jsonthe output is still only JSON. - the database commands (
-
fast-syncreads the indexer's state from systemctl's answer alone. A warning on its error output
made the state unreadable, which fast-sync took as "stopped".
Rewards
- A reply to someone else's listing no longer uses up a user's first-trade bonus (10 BLURT + 10
BLURT Power), from blocks dated 2026-11-01 00:00 UTC. The bonus is paid for the first completed trade
on a listing the user paid for. Before, the user's first reviewed trade of any kind used up the
one-time flag, so a new user whose first trade answered someone else's listing was never paid. Older
blocks keep the old rule, so a resync pays exactly what was paid before, and an account whose flag
was already used up that way stays as it is. - What the site says about rewards now matches what is paid. These statements were false and are
corrected in all ten languages:- "Leave feedback after your free first buy to unlock the 10 + 10 bonus": the free buy has no listing
fee, so it cannot unlock it. - "Save the free buy for later, it never expires": it is offered for the first order only.
- "500 signups a week need about $1 of Blurt": about 51,000 BLURT.
- "Morphit" delegates and can withdraw rewards "for abuse": the relay of the site lends them.
- The 1 BP welcome stake "arrives instantly": it is set aside and lent once the rewards reach the
chain's minimum delegation. - The four FAQ answers on the free first buy, the welcome rewards, loyalty rewards and operator
earnings are retranslated in full from the English, since some translations had drifted.
- "Leave feedback after your free first buy to unlock the 10 + 10 bonus": the free buy has no listing
The website
- The run-a-node page is rewritten. It is shorter and plainer. The download button names the
current version, and the install step shows the one command to run. The operator-tag form is gone:
the guided install offers to register the tag. - The run-a-node page shows what an operator earns and pays. It lists the income (90% of BLURT
listing fees, featured-slot bids and first-message fees on the site) and what the relay pays (about
102 BLURT per new account, the first-trade bonus, Blurt Power lent as rewards, top-ups), with a rule
of thumb for how many paid listings cover one new account. - The home page invites visitors to run a site, with a link to the run-a-node page and to the
running sites. - Visitors see what an account gets. A "What you get" panel on the orderbook lists every reward,
when it arrives and how, with the signup button. After signing up, the success screen shows the same
list and stays up for 20 seconds, with a button to go on at once. A site without an operator tag pays
no rewards, so it does not show the panel. - "Run a node!" is in the footer's Federation menu, between Instances and Compare.
The repository
- A tidier top level.
SECURITY.mdandTHIRD-PARTY-LICENSES.mdare now indocs/.- The configuration example is
ops/env/morphit.config.env.example. - The audit allowlist and the smoke typecheck configuration are in
scripts/. - The Prettier settings are the
"prettier"key ofpackage.json.
scripts/run-smokes-chunk.shnow fails when a smoke fails. It printed "N runners failed" and
still exited 0, so a battery run in chunks read every failing chunk as passed. It now exits non-zero,
asscripts/run-smokes.shdoes.
Releases (maintainer)
- Block 3 is one code block. If the dry-run printed the payload, Block 3 is done. Only a release
without an IPFS CID needs more, and the payload builder then prints the command for morphit.io and
how to retry. - The ceremony writes its files to
/tmp(/tmp/morphit-build-manifest.json,
/tmp/morphit-release.json), not into the repository, and Block 3 clears them first. - Block 4 confirms the broadcast by reading the new blocks. A node that accepts the transaction
without its block number no longer leaves it "NOT confirmed". The other nodes are asked for the blocks
produced since the broadcast, and the transaction is confirmed when one of them holds exactly this id.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
2 downloads
- The main menu reads @morphit's on-chain release record. Before, it asked only git.agorise.net and
-
Morphit v1.21.2
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 39smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m10smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 51smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 4m25smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 46smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h17m23smorphit-release / Build + publish release tarball (push) Successful in 37m3sreleased this
2026-10-08 06:04:39 +00:00 | 23 commits to main since this releaseMorphit v1.21.2
Upgrades that get through a censored network, a warrant canary that keeps renewing on Tor-only servers,
and a release ceremony in the right order.Upgrading:
sudo morphit-ops upgradeon every server, Tor/I2P-only ones included. No database change.
This upgrade is run by v1.21.1's upgrade program; the canary repair below runs from this release during
the upgrade. Every instance must run v1.21.1 or later before 2026-11-01 00:00 UTC, when the stricter
consensus rules start; this release changes none of them.Upgrades
- From the next upgrade, a server that cannot reach the public Blurt nodes still finds the release record. The upgrade asked
its own indexer for the on-chain record for 4 seconds, then the public nodes. On a server whose indexer
reaches the chain over Tor (where the public nodes are blocked), both could fail, and the upgrade
refused the release. When the public nodes fail too, it now asks its own indexer again and gives it
time to answer; the error names both paths when neither answers. This takes effect from the upgrade
after this one (this one is still run by v1.21.1's program): if a server refuses this release with
"all RPC endpoints unavailable", run the upgrade again once its network is better.
Warrant canary
- The weekly renewal runs the installed release's canary code. The canary setup recorded the folder
it was run from (an unpacked copy in~/Downloads/morphiton a wizard install), which no upgrade
updates, so the weekly renewal kept running old code. The setup now records the installed
/opt/morphit, and the upgrade repairs an existing weekly renewal that runs as root: it points it at
the installed release, and rewrites one written by an older setup with the same key, operator, address
and account, the public key exported once from root's keyring, then starts a renewal in the
background. A renewal script in another account's home, an older one that uploads the canary to
another server, or one missing a value is not changed; the upgrade names the command to run. On a
server where the weekly renewal used the old copy, this upgrade's own renewal still runs before the
repair: if its last lines list the warrant canary, run the command they give on that server
(sudo systemctl start morphit-canary.service). - On a Tor-only server the canary carries the Bitcoin block height again. Every Bitcoin explorer
failed over Tor, so the canary's Bitcoin block height read "(unavailable at signing time …)". Theirhttps://addresses are now
reached through Tor with the certificate checked as usual. A failed source now shows the reason, not
only "fetch failed".
Releases (maintainer)
- The ceremony broadcasts the on-chain record before morphit.io upgrades. Since v1.21.0 an upgrade
installs an unsigned release only by its SHA-256 in that record, so the old order (upgrade in Block 3,
broadcast in Block 5) made morphit.io refuse the release ("The release is not signed, and no signed
on-chain release record names its hash"). The blocks now run: Block 3 builds and dry-runs the payload (the
manifest from the published tarball, checked against theverify.jsoninside it), Block 4 broadcasts,
Block 5 upgrades morphit.io, Block 6 checks that morphit.io serves the anchored build and repairs the
canary. If a release has no IPFS CID, Block 3 has morphit.io host the release (installing nothing) with
the release's own seed scripts, taken from the published tarball after checking its SHA-256, and print
the CID. Because the record now reaches every node before it upgrades, a change to what the record may
contain ships in one release and is used only by a later one. - The key prompt of the broadcast scripts stays on screen. Its last line (in the snapshot scripts,
the whole "Paste the … POSTING WIF" line) was erased the moment it appeared, so they seemed never to
ask for the key. - A broadcast a node accepts without a block number is looked up on the other nodes by its
transaction id, and reported as confirmed once another node lists it in its block, instead of "NOT
confirmed by a second node". An answer counts only for exactly this id, in a block the transaction
can be in; the nodes are asked together each round, until the transaction has expired. A
"duplicate transaction" answer is looked up the same way.
Downloads
-
Source code (ZIP)
1 download
-
Source code (TAR.GZ)
6 downloads
- From the next upgrade, a server that cannot reach the public Blurt nodes still finds the release record. The upgrade asked
-
Morphit v1.21.1
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 40smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m5smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 44smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 4m12smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 45smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h14m13smorphit-release / Build + publish release tarball (push) Successful in 35m26sreleased this
2026-10-07 18:28:57 +00:00 | 24 commits to main since this releaseMorphit v1.21.1
A calmer upgrade, a working language filter, branded Blurt post pictures, and fixes to the consensus
rules before they switch on.Upgrading:
sudo morphit-ops upgradeon every server, Tor/I2P-only ones included. Every
instance must run v1.21.1 before 2026-11-01 00:00 UTC, when the stricter consensus rules start
(v1.21.0 is not enough: this release corrects some of them). One small database migration (a column
description) runs by itself at start-up. This upgrade is still run by v1.21.0's upgrade program: read
any warning lines it shows, even if its last lines say there is nothing else to do.Consensus rules (from 2026-11-01)
- A featured-slot bid's place no longer depends on when a server's own fee re-check happened to run:
every instance reaches the same answer. - The look-alike name check gives the same answer on every Node.js version.
- The site no longer sends text every instance would drop (some invisible characters): an order with
one would have lost its listing fee. "Mark complete / review" sends the completion before the review,
so the review is not dropped. Profile links are sent in the form instances store.
Upgrade output
- The upgrade prints what changed and what is left for you, not every routine check ("✓ N other checks
found nothing to change"). From the upgrade after this one it ends with one summary: "Left for you:"
(with the commands), or "Nothing else to do." — including how the background web-proxy checks ended. - Every long step shows the spinner; a failed step keeps its full output in
/var/log/morphit/. - On a Tor/I2P-only server the frontend's web-server base image is fetched through Tor in the
background and the frontend rebuilt on it; nothing to do by hand.
Orderbook
- The language filter works. A language filter shows only orders written in the chosen languages;
with no language chosen, every order shows, including those posted before v1.15.0 (they carry no
language). The filter you leave on the orderbook is kept for your next visit on that device.
Open to every country
- No instance blocks visitors by country. People behind national firewalls (China, Iran, North
Korea, …) must be able to reach the instance of their choice; that is what federation is for. The
upgrade empties a BunkerWeb country list (BLACKLIST_COUNTRY,WHITELIST_COUNTRY, also per-site
ones) in BunkerWeb's settings file, removes one saved in BunkerWeb's web UI from BunkerWeb's database
(keeping a copy of the database first), and checks BunkerWeb runs without one; a list set any other
way is named in the upgrade's output and insudo morphit-ops status, with where to clear it.
v1.21.0's note that country blocks "still work" is withdrawn. - The instances page badge reads "🏅 Zero use of clearnet internet" again.
Branding
- Blurt posts show the instance's own picture, never Morphit's on a branded instance — also when
the brand cannot be read at that moment (then no picture). Blurt loads such a picture only from an
https://address, so a post made over Tor or I2P carries none. Unbranded instances keep Morphit's
pictures. A logo given without a name no longer puts "Morphit" next to it in the preview picture,
and an ownog-image.pngthat is not 1200 × 630 is named in a warning. Seedocs/BRANDING.md.
Security
- Root's files no longer live where the service account could redirect them: the web-proxy and
mirror state moved to/var/lib/morphit-ops/,/var/log/morphitbecomes root's (the upgrade fixes
existing servers), and nothing root writes follows a link there. - The MCP server limits each visitor, not everyone behind the web proxy together, and counts every
call in a batch. Its SDK is updated to 1.32.1.
Releases
- A release whose IPFS address could not be computed is no longer broadcast without one: the
ceremony's Block 4 stops and says how to pass the address the release server printed. - The release notes now live in
docs/release-notes/and the claims list is
docs/MORPHIT-BRAG-LIST.md.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
2 downloads
- A featured-slot bid's place no longer depends on when a server's own fee re-check happened to run:
-
Morphit v1.21.0
StableAll checks were successfulmorphit-ci / Supply-chain audit gate (every advisory triaged, none fixable in range) (push) Successful in 41smorphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 1m25smorphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 57smorphit-ci / Integration tests (real Postgres 16) (push) Successful in 9m14smorphit-ci / ansible-lint (playbook quality gate) (push) Successful in 57smorphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 1h12m35smorphit-release / Build + publish release tarball (push) Successful in 35m56sreleased this
2026-10-05 20:43:23 +00:00 | 28 commits to main since this releaseMorphit v1.21.0
A full security and privacy review of the whole codebase, done the way a hostile expert would: 19
independent reviewers, a red team against a running instance, a fresh threat model, and four rounds of
fixes, each checked by reviewers who had not seen the fix. Every fix comes with a test that was run
against the old code and seen failing.Upgrading: clearnet servers run
sudo morphit-ops upgradeas usual (see "Every node" below for the
new--questionsand--heals). Zero-clearnet servers must use the signed offline bundle — follow
"Zero-clearnet nodes" below step by step. There is one database migration (new indexes, and stored
push-subscription browser details removed); it runs by itself at start-up.New consensus rules switch on at 2026-11-01 00:00 UTC (by block timestamp, so every indexer agrees).
Please upgrade every instance before then. The rules are listed under "Marketplace" below.Indexer: things one user or one node could break
- One cheap on-chain operation could stop every indexer for good. Two duplicate fee-bearing operations
in one transaction, or a deeply nested JSON operation of about 6 KB, made every indexer retry the same
block forever. Both now fail only that operation; indexing goes on. - A single RPC node could feed the indexer unsigned "official" operations (a release record or a new
RPC node list) and so add its own nodes to the pool or change the treasury. Official operations are now
accepted only with a valid signature from the pinned key. - Trusted reads (posting keys, snapshots) need operators to agree, and a stale answer never wins. A
value is confirmed only when at least two operator names agree and form a majority; an answer that is
provably older is overruled, and a lone disagreement delays confirmation instead of deciding it.
Operators are counted by node name. - One node answering errors no longer freezes indexing; the pool moves on to the next node.
- Peer price federation works. A field-name mismatch meant no peer price was ever counted.
- Memory and load limits: RPC replies are capped by what was asked for, account-history reads have
per-client and total limits (413 reply_too_large,503 history_busy), the indexer has a 1536 MiB
memory cap, and the database gets per-request timeouts, missing indexes and no JIT stalls.
Privacy
- BunkerWeb contacts no one. As shipped it sent blocked visitors' IP addresses, full URLs and request
headers to its maker's service, looked every visitor up in public DNS blocklists, and downloaded lists and
databases from third parties. All of that is off, on new and upgraded servers alike. - Fee checks and prices go over Tor first. BTC fees are checked with onion block explorers, XMR fees
with onion xmrblocks explorers, and BTC/XMR prices come from the agreeing median of five Haveno and Bisq
price nodes over Tor. Clearnet sources are only a fallback, and never used on zero-clearnet nodes —
which now offer BTC and XMR fees again. - The relay no longer writes visitor network prefixes or account names to its log, stores no browser
details with push subscriptions, and only sends Web Push to the real push services. - The browser's release check: two small requests to one node, once a day, shared by all tabs. The
browser now checks the release signature itself, so one node cannot forge it, and a release older than
the running site never supplies fee addresses. - Nothing about who you are survives Sign Out or a "just this session" sign-in in another tab, the
profile cache or chat state; account-named server answers are no longer cached by the browser. - The public health pages show only status; host memory, disk and counters need the local header.
- Every instance uses its own address in page links and previews; zero-clearnet instances carry no
clearnet address at all.
Chat
- Messages now prove who sent them. New messages use an authenticated format, so the operator's server
cannot insert a message "from" the other trader. Older messages still open but are marked unverified and
never offer "Pay now" or change a trade. - "Verify peer" is a 60-digit safety number (it was 64 bits, which a determined attacker could match).
Compare once more after upgrading. - A changed chat key always asks you first, Lock keeps your comparisons, and a replaced key can only
open old messages.
Keys and sign-in
- The page's Content-Security-Policy no longer allows inline or eval'd scripts.
- Removing or hardening a YubiKey can no longer be undone by a later password change; the YubiKey
path also asks for your 2FA code when 2FA is on. - Decrypted keys are no longer written to disk during a page reload.
Marketplace
- A stranger can no longer mark your order "paid"; payments are checked against the amount you asked
and the actual counterparty, and a payment with no amount asked shows as "received", not "paid". - Prices shown in the app are live, from the indexer; when none is known the pay field stays blank.
- Rules that switch on at 2026-11-01 00:00 UTC: deeper-than-64-level payloads and U+FFFE/U+FFFF text
are rejected; a review must cite an order the two of you discussed or completed; attestor loyalty counts
only the treasury's share; feature bids under the step are queued, and only live, paid orders rank;
display and operator names are checked for look-alikes of reserved names; profile fields are validated;
chat read receipts are bounded; an order replacement offering only disabled payment methods is refused.
Servers
- Services no longer run as root where they don't need to, and the service account can no longer gain
root through files it owns. - TLS certificates renew on BunkerWeb servers (they could not before), and hardening no longer cuts off
Docker's forwarding. - Zero-clearnet servers enforce it: only Tor and i2pd may reach the internet; DNS goes nowhere but the
box itself; the Matrix alert bot is refused unless it goes over Tor to an onion homeserver. - Upgrades verify the release against the on-chain record or the pinned signing key on every path, and
zero-clearnet upgrades install nothing from the internet. - Branded instances get their own link-preview image, drawn from their logo and name.
Repository
- Internal working notes, personal details and process records are no longer in the public repository.
The threat model (docs/audit/2026-10-*) and docs were rewritten to match the code; claims that were not
true were corrected or removed. - Vulnerability reports: Matrix direct message to
@agorise:matrix.orgonly (see SECURITY.md).
Every node: questions and repairs after the upgrade
The repair part of the upgrade never waits for an answer now. A question asked part-way through could hold up
the upgrade or cut it off. On the upgrade to this release, the old upgrader's own two questions (described below) still
wait unless you pass--yes.Where the repairs used to ask, they now take the safe choice and tell you:
- the journal is left as it is;
- on a tor-only node, a Matrix bot on a clearnet homeserver is stopped;
- plain-text backups are left as they are.
sudo morphit-ops upgrade --questions, run from a terminal, asks those questions. Each upgrade lists the
questions it left on its last lines.When a line says "the next
sudo morphit-ops upgradetries again", that is now true even when you are already on
the newest release. A plainsudo morphit-ops upgradeon an up-to-date box prints "✓ Already on the latest
release." and then re-checks this release's repairs; nothing is downloaded or installed.--check-onlyand--json
still only look.sudo morphit-ops upgrade --healsdoes the same directly, without checking for a release first. Use it when a
line asks you to, or when an upgrade says its repair step ran out of time.Tor-only node, Matrix bot kept on a clearnet homeserver (
KEEP-CLEARNET): the rule that lets only Tor and i2pd
reach the internet is then not loaded on that node, and the upgrade says the node is not zero-clearnet while the bot
is kept. The rule would cut the bot off, including the DNS lookups it needs. To get the rule:- Move the bot to a homeserver on the node or a
.onionone:sudo morphit-ops matrix setup. - Run
sudo rm /etc/morphit/matrix-bot.tor-only-decision. - Run
sudo morphit-ops upgrade --heals.
Zero-clearnet nodes: upgrade from the signed offline bundle
On a zero-clearnet node, do not run the plain upgrade for this release. That includes menu option 2 and a bare
sudo morphit-ops upgrade. The upgrader already on your box (v1.20.3 or older) would then install the packages withnpm ci
from the npm registry over the clearnet.Use the offline bundle instead. The release job builds it, and it is signed with the release key your box already
trusts, so nothing on the box touches the clearnet and npm is not used.On your own computer (any computer with internet), download the two files from the release page. The bundle is
about 250 MB: 246.5 MB measured when it carries its Node.js and Kubo runtimes. Without the runtimes it is
135.0 MB; Kubo v0.42.0 is 54.6 MB and Node.js v22.22.2 about 57 MB.curl -fLO https://git.agorise.net/agorise/morphit/releases/download/v1.21.0/morphit-v1.21.0-offline.tar.gz curl -fLO https://git.agorise.net/agorise/morphit/releases/download/v1.21.0/morphit-v1.21.0-offline.tar.gz.ascCopy both to the node, logging in the way you normally do. Use
scp -O, not plainscp:scp -O morphit-v1.21.0-offline.tar.gz morphit-v1.21.0-offline.tar.gz.asc <you>@<your-node>:/tmp/On the node, in a terminal:
-
Check that the node can verify the signature. Each command must print something, and neither may say
"No such file" or "command not found":gpg --version | head -1 ls /opt/morphit/.forgejo/release-signers/agorise.asc -
Run the upgrade from the bundle.
--yesanswers the two questions the old upgrader asks; they would
otherwise wait for you with no time limit:sudo morphit-ops upgrade --from-file=/tmp/morphit-v1.21.0-offline.tar.gz --yesYou should see these three lines, in this order:
✓ Integrity verified (gpg-signature).Offline bundle detected (prebuilt node_modules) — skipping npm ci; no registry needed.Using the prebuilt web frontend shipped in the release (no rebuild).
Let it run until
✓ Success — your Morphit server is now running v1.21.0(about two to three minutes).The rest of the output comes from the old upgrader already on your box, which cannot be changed. Read it like this:
- Without
--yes, it asks "Apply upgrade from v1.20.x to v1.21.0? … This will: … run npm ci, rebuild + redeploy
the web frontend …". That text is old. With the bundle, nothing is installed from npm and nothing is rebuilt
(see the two lines above). Answery. - Without
--yes, a box that has never had a warrant canary may also ask "Set one up now, right here on this
box? …". Answern. The upgrade then goes on, and you can set a canary up any time later with
sudo bash /opt/morphit/scripts/canary/setup.sh. - If your Matrix bot is set up, it prints "Matrix alert username configured — enabling + restarting
morphit-matrix-bot…". On a tor-only node whose bot uses a clearnet homeserver, ignore it. The bot refuses to
start, and the background checks (step 4) switch it off again. To keep the bot on its clearnet homeserver
anyway, use step 3. - It ends with "Congratulations! … nothing else to do". That is not true for this release: carry on with
step 3.
-
Answer the questions the upgrade did not stop for: the old relay log lines, the Matrix bot, and plain-text
backups. Any it does not need to ask, it skips:sudo morphit-ops upgrade --questions -
Read what ran after the services restarted:
sudo cat /var/log/morphit/after-upgrade-heal.logThe last line must be
Done.. If it is not, the checks are still running: they wait up to 15 minutes for the
services to restart and then up to 10 minutes for the background web repairs. Wait a minute and read it again. -
Once
Done.is there, run the repairs once more. This picks up whatever had to wait until Docker pulls through
Tor, which the checks in step 4 set up. One example is the frontend's newer nginx base, if a line said the
frontend "stays on its current nginx base for now". Nothing is downloaded over the clearnet:sudo morphit-ops upgrade --heals -
Remove the two files:
rm /tmp/morphit-v1.21.0-offline.tar.gz /tmp/morphit-v1.21.0-offline.tar.gz.asc
If something goes wrong:
Cannot verify the integrity of release v1.21.0: nothing was changed. The two files must sit side by side
under exactly these names. Download the.ascagain and repeat step 2. If the same error also says "No on-chain
hash available … Start it with: sudo systemctl start morphit-indexer", ignore that hint. the old indexer never
stores the bundle's hash, so starting it does not help. Only the.ascdoes.Could not import release-signer key agorise.asc: gpg could not start its helper. Run step 2 as
sudo env TMPDIR=/tmp morphit-ops upgrade --from-file=/tmp/morphit-v1.21.0-offline.tar.gz --yes.- A line starting
The upgrade stopped its heal step at the time limit: wait until the upgrade has finished,
then runsudo morphit-ops upgrade --heals.
What this upgrade changes on installed servers, by itself
-
BunkerWeb no longer contacts anyone. These were already off: BunkerNet, DNS blocklists, the reverse-DNS
black/white/grey lists, the anonymous report and third-party captchas. Now:- its daily GeoIP download (db-ip.com), release check (api.github.com) and "preview" Pro-plugin download
(assets.bunkerity.com) are replaced: the upgrade mounts Morphit's own job lists into BunkerWeb's scheduler, and
country rules use the GeoIP file inside the BunkerWeb image; - reverse scan and plugin downloads stay off;
- BunkerWeb's in-memory list of the last 100 blocked requests is off (
USE_METRICS=no). That list held each
visitor's address, full URL and browser with no time limit.
- its daily GeoIP download (db-ip.com), release check (api.github.com) and "preview" Pro-plugin download
-
BunkerWeb's blacklist is off, and part of it cannot be replaced. BunkerWeb checks every blacklist entry only
after a reverse-DNS lookup of each visitor's address, which tells outside DNS servers who visits your site. With
the blacklist off:- Addresses and networks you listed (
BLACKLIST_IP) keep working. The upgrade moves them into an nginxdeny
rule (CUSTOM_CONF_SERVER_HTTP_morphit_ip_blocks) and says so. - Network (ASN) blocks, reverse-DNS name blocks, user-agent and URL lists no longer apply. The upgrade names
each one it finds. Ansible-installed servers hadBLACKLIST_ASN=AS14061 AS24940 AS16276(DigitalOcean, Hetzner,
OVH); visitors from those networks, VPN users among them, are no longer turned away. - The Tor-exit list and the downloaded bad-bot list are no longer used.
- Country blocks (
BLACKLIST_COUNTRY) still work, from the GeoIP file on the server.
- Addresses and networks you listed (
-
Kubo (IPFS) takes no settings from the internet. AutoConf, HTTP routers (cid.contact, delegated-ipfs.dev) and
DoH resolvers are off. A clearnet node seeds over the public DHT, joined through the standard bootstrap peers. -
Ubuntu's own fetches a server does not need are off on every node:
- the login banner's news (motd.ubuntu.com) and apt's Ubuntu Pro news;
- the release-upgrade check at login (changelogs.ubuntu.com;
Prompt=neverin
/etc/update-manager/release-upgrades). To move to a new Ubuntu release later, set it back toPrompt=ltsand
runsudo do-release-upgrade; - fwupd's firmware-list refresh and pollinate;
- rkhunter's data-file update. Ubuntu's rkhunter cannot download one anyway; its data comes with the apt package.
snapd and Ubuntu Pro's status check stay on: installed snaps and a Pro subscription need them.
-
Zero-clearnet nodes can reach their own local network again. The rule that lets only Tor and i2pd reach the
internet now also allows the local network (10/8, 172.16/12, 192.168/16, IPv6 fc00::/7), so a NAS, a printer or
your laptop work as before. DNS goes nowhere but the box itself: it is refused to the local network, to
link-local addresses (home routers often announce their fe80:: address as the resolver) and to the internet, over
IPv4 and IPv6, from every program — Tor, i2pd and the containers included (none of them needs it). -
No Docker Hub download on a zero-clearnet node. The frontend moves to this release's pinned nginx base image
only when that image is already on the box, can be loaded from avendor/docker/file you put there, or can be
fetched with Docker going through Tor. Otherwise it keeps its current base and says so; once Docker pulls through
Tor,sudo morphit-ops upgrade --healson the server switches it. (The release's offline bundle carries no Docker
images.) -
Running the indexer and relay as their own users (not root) is now checked where each one really listens, and
each gets up to two minutes to start. A service that runs as its user but has not answered yet keeps running as
its user, and the upgrade says so. Only a service that is down, keeps restarting or runs as someone else is put
back on root. -
The indexer has a memory cap (1536 MiB, systemd
MemoryMax), like the relay (512 MiB) and the MCP server
(256 MiB). A burst of large requests can no longer take the whole box. The cap is about twice the most the indexer
was measured to use honestly.sudo morphit-ops upgradechecks that the running indexer carries it; if the
indexer happens to use more than 80% of the cap at that moment, nothing is changed and the upgrade says so.
The indexer now reads its own cap, so the optional flow catch-up sizes its buffer to fit. -
Served web files stay with the canary user. The service-user heal no longer hands
apps/web/staticback to
root (it already leftapps/web/buildalone).
Releasing (maintainer)
The offline bundle. The release job now builds it itself, without Docker, and attaches it with its
.sha256.
Without the bundle the release is not published. The job signs the tarball and the bundle only when the
MORPHIT_RELEASE_SIGNING_KEYsecret is set; otherwise it attaches no.asc, and a node running this release
installs later ones by the SHA-256 in @morphit's signed on-chain record. For this release only, the maintainer signs
the bundle and attaches its.asc, because the upgrader on v1.20.x zero-clearnet nodes accepts the bundle only with
a signature.The bundle carries no OS packages or Docker images. A fully offline fresh install still needs the full appliance
bundle:bash scripts/build-offline-bundle.shon an Ubuntu 24.04 box with Docker. That build is optional and not
part of the release steps.Moved tags. The release job checks that the tag still points at what you signed. If a release for the tag already
exists, the job attaches to it only when it was built from the same signed tag object. A tag moved back to an older
signed object after publishing is therefore refused before anything is attached, and nothing is published for it.Block 4 also checks that the release job built the very tag you pushed in Block 2. If it stops with "the tag was
moved after it was pushed", do not broadcast. Delete that release on git.agorise.net, codeberg.org and gitea.com,
because its tarball, bundle and signatures are already published there.Neither check adds a command.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
2 downloads
- One cheap on-chain operation could stop every indexer for good. Two duplicate fee-bearing operations
-
Morphit v1.20.3 Stable
released this
2026-10-02 04:48:05 +00:00 | 32 commits to main since this releaseMorphit v1.20.3
Visitors' browsers contact a Blurt node far less often, and pages download less. There are no
database changes.Privacy
- The release check reaches a Blurt node at most once a day. To make sure an operator is not
keeping visitors on an old build, each browser asks a public Blurt node for Morphit's signed
release record — the one request that leaves the site, and that node sees the visitor's IP. It
ran on every visit. A good answer is now remembered in the browser for 24 hours (and asked again
right after the site updates), so further visits that day contact no one. - That request is much smaller: it reads @morphit's last 100 history entries instead of 10,000
(a few KB instead of about 115 KB), and looks further back only if it must. - The FAQ says exactly what goes out ("Does anything see or leak my IP address…"), in every
language: at most once a day, two small requests.
Faster pages
- The served build's version file is downloaded once per page load, not twice. The release
check and the update check both need it, and it is about 80 KB.
Release fixes
- Zero-clearnet instances can always upgrade. v1.20.2 was first broadcast without its IPFS name,
and a Tor/I2P-only instance refused it. The release builder now always includes the name, warns
when a release has no IPFS address, and refuses an IPFS record left over from an earlier release.
A zero-clearnet upgrade also accepts a release located by its IPFS address alone. - The release build retries the IPFS tool download (and has a second source), so a slow
download no longer leaves a release without an IPFS address. - The ceremony's Block 4 clears values an earlier ceremony left in the terminal.
Upgrading
Run
sudo morphit-ops upgradeon each server. Nothing needs doing by hand.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
4 downloads
- The release check reaches a Blurt node at most once a day. To make sure an operator is not
-
Morphit v1.20.2 Stable
released this
2026-10-02 00:51:51 +00:00 | 33 commits to main since this releaseMorphit v1.20.2
Pages load faster and are easier to read, Bitcoin fees go to a separate address for each order,
Monero fee checks no longer depend on two websites, and the compare page works again. There are
no database changes.Faster pages
- Each page downloads about half the text it used to. The FAQ, the privacy guides, "run a
node" and the cheat sheet now load only with their own page. Before, every page downloaded all
of them (and, in any language but English, the English copy too): about 100 KB less per page,
and 200 KB less for a visitor reading another language. - The logo shows first. The browser now fetches the header logo before the app's code, keeps
its space reserved while it loads (nothing jumps), and downloads it once instead of twice. Its
occasional shine is drawn by the graphics card instead of repainting the logo. - Fonts: one font file was downloaded twice under two names; it is now downloaded once, all
three fonts start loading at once, and the browser keeps them for a month. - The update check waits. The check for a newer version (an 80 KB file) no longer competes with
the page while it loads, and no longer runs on every switch back to the tab. - On a simulated slow phone, the home page's PageSpeed score went from 61 to 77–80; accessibility
and SEO from 96 and 92 to 100.
Easier to read and to find
- Grey text is readable. The muted grey used for hundreds of labels was too faint on the dark
background (3.4:1); it now meets the 4.5:1 readability standard everywhere. Operator colour
themes get the same lift. - A missing file is a real "not found". Asking for a file that does not exist (for example
/.well-known/ai-catalog.jsonor/favicon.ico) used to return the app's page, so search
engines and AI tools were told those files exist. They now get a proper 404. - Screen readers: the "Start" button says what it does (sign in or create an account), the
logo links no longer announce an English "home" in every language, and the footer's headings are
in the right order. - Pages are isolated from other sites' windows (Cross-Origin-Opener-Policy).
- The privacy guide list showed a raw text key for goods trades (which have no guide). Fixed.
New — fees
- Each Bitcoin fee gets its own address. This release pins the treasury's Bitcoin account key.
From this release on, every order paid in BTC gets a fresh address of that account, and a
payment to it can only ever count for that one order. Nobody can claim someone else's payment. - More sources check Monero fees, and payers don't get stuck.
- Three public Monero nodes join the three explorers. A node gets only the transaction id (never
the payer's transaction key), and the indexer checks the payment itself, so a node cannot fake
one. - Two sources still have to agree. If only ONE can be reached for two hours and nothing
contradicts it, its answer is accepted once the payment is 10 blocks deep. Sources that
disagree never settle it; the log names what each one said. - The upgrade removes the three explorers that stopped answering (still listed on nodes set up
before v1.20.0) and adds the newer sources, once. A default you remove later stays removed.
- Three public Monero nodes join the three explorers. A node gets only the transaction id (never
Fixed
- The compare page. It could not reach other instances at all: each page's security policy
lets the browser talk only to its own instance, so the request was refused before it left
("Failed to fetch"). The instance now fetches the other instance's orderbook itself, only for
instances registered on chain, over their onion address when they have one. Messages are clear
and in every language. - Pages switching language by themselves. On a slow connection, a browser set to another
language could turn an English page into that language a few seconds after it loaded. The
page's own language now always wins. - The treasury setup scripts. The Bitcoin key script lost the key when run as documented, and
the Monero self-test stopped before printing anything when run from the repo folder. Both work
now. The Bitcoin script also refuses an account that has ever received coins. - A dependency. devalue (used by SvelteKit) is updated to 5.9.4 for three advisories.
New — checks
- Block check (report only). For every block, the indexer recomputes the chain's own
fingerprints (the transactions' merkle root, the block id and its link to the block before) and
counts whether they match what the RPC node served. Nothing is refused yet.sudo morphit-ops healthshows it as "Block check".
Upgrading
Run
sudo morphit-ops upgradeon each server. Nothing needs doing by hand.- The Monero source list is updated by the upgrade where needed.
- The web container is rebuilt from this release's config (missing files, font caching, the
opener policy) — on clearnet and on Tor/I2P-only servers alike. - Check
sudo morphit-ops health→ "Block check" a day after upgrading.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
6 downloads
- Each page downloads about half the text it used to. The FAQ, the privacy guides, "run a
-
Morphit v1.20.1 Stable
released this
2026-10-01 03:16:50 +00:00 | 34 commits to main since this releaseMorphit v1.20.1
A fix release for problems found while upgrading the live instances to v1.20.0. There are no
database changes and no changes to on-chain operations.Fixed — upgrades and operations
- BunkerWeb could stop taking any new settings.
- Morphit's firewall exception for its API was stored twice on some servers. With two copies,
BunkerWeb rejects every new config it builds and quietly keeps serving the last one that
worked. On one instance that had been true for three weeks, so settings changed since then,
including the one that stops visitors choosing their own IP address, never took effect. - The upgrade now keeps exactly one copy and removes the others, after a backup of BunkerWeb's
database. It then checks on the live site that the API still gets through and the rest of
the site is still protected, and puts the copies back if not. - The upgrade now reads BunkerWeb's own verdict on every change. If BunkerWeb refuses a config,
you see nginx's reason instead of a vague "not applied yet".
- Morphit's firewall exception for its API was stored twice on some servers. With two copies,
- Slow BunkerWeb servers finish their settings change.
- Where BunkerWeb's downloads time out, it needs minutes to rebuild its config after a change,
which is longer than the upgrade could wait. The change was always put back. - On a BunkerWeb server the privacy and header settings are now applied in the background, for
as long as BunkerWeb needs. The upgrade shows the progress while it can, and
sudo morphit-ops statusshows the result under "Web proxy (BunkerWeb)".
- Where BunkerWeb's downloads time out, it needs minutes to rebuild its config after a change,
- A relay that stopped could stay stopped. The relay could end without an error, so systemd
did not restart it, and the upgrade then skipped it because it was not running. One instance's
relay was down for three days this way, and sign-ups there failed.- The relay and the indexer now restart after any exit.
- A relay that ends without being asked to logs why and exits with an error.
- The upgrade starts an enabled relay that is not running, and checks that it stays up.
- The sign-up limits work. The relay could not reach its state folder, so the daily sign-up
ceiling was never saved and aSIGNUPS_DISABLEDfile was never seen. The folder is now
/var/lib/morphit-relay. The upgrade moves anything already in the old one, so paused sign-ups
stay paused, and/var/lib/morphit/relaynow points to the new folder. - The release ceremony's payload step installs its packages first (
npm ci), so it cannot
run against outdated ones on the maintainer's computer.
Upgrading
Run
sudo morphit-ops upgradeon each server. Nothing needs doing by hand.- On a BunkerWeb server, the upgrade ends with the result of the background settings change,
or says it is still running. Check it later withsudo morphit-ops status. - Signed-up counts: the first day after the upgrade starts a fresh daily count, because the
old count was never saved.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
2 downloads
- BunkerWeb could stop taking any new settings.