Warning
This is a beta of Meridian 4. Nobody gets it automatically: pip, uv, the install script, and meridian update on 3.x all skip it. Your 3.x servers keep working.
Use a separate, fresh server you can wipe. Meridian 3.x and 4 cannot share a server: both need port 443. Meridian 4 refuses to deploy onto a server that still runs 3.x; replacing a 3.x server means tearing it down first, and every one of its users needs a new link.
Try it next to 3.x
You need uv (macOS or Linux; on Windows use WSL). On your computer Meridian 4 keeps its state in ~/.config/meridian, so your 3.x command and ~/.meridian stay untouched:
curl -LsSf https://astral.sh/uv/install.sh | sh # installs uv and uvx; open a new terminal afterwards
alias meridian4='uvx --prerelease allow --from meridian-vpn@latest meridian'
meridian4 deploy 198.51.100.10 # IP of the separate serverWhen the deploy finishes, meridian4 panel prints the address of the web panel, where you manage people and API tokens from a browser, and a one-time link to set its password. Treat both like passwords.
Prefer questions to flags? meridian4 setup walks you through one server or several (exits in other countries, relays) in English, Russian, Persian, or Chinese. The alias always runs the newest beta; after a new one comes out, meridian4 apply brings your servers up to date.
Already running an earlier 4.0 beta? Those deployed Remnawave; b9 replaces it with Meridian's own control service. Run meridian4 migrate once: it keeps every client link, key, limit, expiry, and traffic count, and checks the links are unchanged before it removes Remnawave. It first backs up the panel's database to ~/.config/meridian/backups/ on your computer and to /var/backups/meridian-migration/ on the control server; there is no rollback, the backup is the way back. It resumes if interrupted. Panel-only data is not carried over (the panel's admin account, per-day usage history, HWID device lists, plugins, and client IP forwarding), and the review lists it.
Keep ~/.config/meridian. It is how Meridian 4 manages your servers. After every change, each computer that manages the fleet saves an encrypted snapshot of the control service, and your first deploy shows a recovery key once: write it down and keep it offline. If the control server is lost or seized, meridian4 restore --to NEW-SERVER rebuilds it from the newest snapshot (on a bare IP, every link changes and is printed; with a domain they stay). See the recovery guide. When 4.0 is released, install meridian the usual way and it manages the same servers; nothing to move or redeploy. Set up with an earlier alias that pointed at ~/.meridian-v4? Drop that part; Meridian finds the folder on its own.
Then, from a device inside the censored network, run:
meridian4 test 198.51.100.10 # does real traffic pass from here?
meridian4 test --probe 198.51.100.10 # does the server look like a VPN server from here?Known gaps: the control server cannot be moved with node replace, only rebuilt with restore; client IP forwarding and per-user IP limits are not available (the control service stores no client addresses); and a server you remove should still answer, or its cleanup cannot finish: if it is gone, add --forget-unreachable to let Meridian forget it.
Tell us what you see
Open a Meridian 4 beta report. The most useful details: your country and network type (home ISP or mobile operator), whether your client app connects, and the output of meridian4 test; for deploy problems add meridian4 doctor. People you shared a connection page with can open "Not connecting?" on it, run the check, and send you the copied report: it contains no links or addresses. Outputs hide secrets, but replace IPs, domains, and links before posting.
Warning
Это бета-версия Meridian 4. Она не устанавливается сама: pip, uv, установочный скрипт и meridian update в 3.x её пропускают. Ваши серверы на 3.x продолжают работать.
Используйте отдельный новый сервер, который не жалко переустановить. Meridian 3.x и 4 не могут работать на одном сервере: обоим нужен порт 443. Meridian 4 откажется разворачиваться на сервере, где ещё работает 3.x; чтобы заменить такой сервер, его сначала нужно очистить, и всем его пользователям понадобится новая ссылка.
Как попробовать рядом с 3.x
Нужен uv (macOS или Linux; на Windows через WSL). На вашем компьютере Meridian 4 хранит своё состояние в ~/.config/meridian, поэтому команда 3.x и папка ~/.meridian останутся как есть:
curl -LsSf https://astral.sh/uv/install.sh | sh # ставит uv и uvx; затем откройте новый терминал
alias meridian4='uvx --prerelease allow --from meridian-vpn@latest meridian'
meridian4 deploy 198.51.100.10 # IP отдельного сервераКогда развёртывание закончится, meridian4 panel покажет адрес веб-панели, где в браузере управляют людьми и API-токенами, и одноразовую ссылку для задания пароля. Относитесь к обоим как к паролям.
Удобнее отвечать на вопросы, чем писать флаги? meridian4 setup проведёт через настройку одного сервера или нескольких (выходы в других странах, реле) на русском, английском, персидском или китайском. Алиас всегда запускает самую свежую бету; после выхода новой meridian4 apply обновит ваши серверы.
Уже запускали раннюю бету 4.0? Она разворачивала Remnawave, а b9 заменяет его собственным сервисом управления Meridian. Выполните один раз meridian4 migrate: он сохраняет все ссылки клиентов, ключи, лимиты, сроки и счётчики трафика и проверяет, что ссылки не изменились, прежде чем удалить Remnawave. Сначала он делает резервную копию базы панели в ~/.config/meridian/backups/ на вашем компьютере и в /var/backups/meridian-migration/ на управляющем сервере; отката нет, вернуться можно только из копии. После прерывания команда продолжает с того же места. Данные, которые есть только в панели (учётная запись администратора, посуточная история трафика, списки устройств HWID, плагины и передача IP клиентов), не переносятся, и обзор их перечисляет.
Не удаляйте ~/.config/meridian. Через эту папку Meridian 4 управляет вашими серверами. После каждого изменения каждый компьютер, управляющий флотом, сохраняет зашифрованный снимок сервиса управления, а первое развёртывание один раз показывает ключ восстановления: запишите его и храните офлайн. Если управляющий сервер потерян или изъят, meridian4 restore --to НОВЫЙ-СЕРВЕР восстановит его из свежего снимка (при адресе-IP все ссылки меняются и выводятся на экран; с доменом остаются прежними). См. руководство по восстановлению. Когда выйдет 4.0, установите meridian обычным способом, и он будет управлять теми же серверами: ничего переносить и разворачивать заново не нужно. Настраивали раньше с алиасом, указывавшим на ~/.meridian-v4? Уберите эту часть: Meridian найдёт папку сам.
Затем с устройства внутри сети с блокировками выполните:
meridian4 test 198.51.100.10 # проходит ли реальный трафик отсюда?
meridian4 test --probe 198.51.100.10 # похож ли сервер на VPN-сервер, если смотреть отсюда?Известные ограничения: управляющий сервер нельзя перенести командой node replace, только восстановить через restore; передача IP клиентов и лимиты по IP недоступны (сервис управления не хранит адреса клиентов); удаляемый сервер должен отвечать, иначе его очистка не завершится: если сервера больше нет, добавьте --forget-unreachable, и Meridian его забудет.
Расскажите, что получилось
Откройте отчёт о бете Meridian 4. Важнее всего: страна и тип сети (домашний провайдер или мобильный оператор), подключается ли клиентское приложение, и вывод meridian4 test; при проблемах с развёртыванием добавьте meridian4 doctor. Те, с кем вы поделились страницей подключения, могут открыть на ней «Не подключается?», запустить проверку и прислать вам скопированный отчёт: в нём нет ссылок и адресов. Секреты в выводе скрыты, но перед публикацией замените IP-адреса, домены и ссылки.
[4.0.0] - Unreleased
Meridian 4 is a new foundation. Its own control service and web management
panel replace 3x-ui; one reviewed topology in ~/.config/meridian/cluster.yml
describes your whole fleet; a small agent on every server applies it; and no
server needs Docker. The first section lists what changed since the previous
beta, 4.0.0b8; the second is what 4.0 changes compared with 3.x.
Since 4.0.0b8
Read first: moving a Remnawave fleet
meridian migratemoves a fleet deployed by an earlier 4.0 beta onto the
control service in place, keeping every link. It backs up the panel's
database to your machine and to the control server, carries each client over
with their keys, subscription ID, status, limits, expiry, and traffic,
replaces each node's container with the agent, checks that every
subscription link is unchanged, and only then removes Remnawave. It is
resumable and has no rollback; the backup is the way back.meridian deploy
offers it when it finds a Remnawave fleet.- Panel-only data is not carried over, and the review lists it: the panel's
admin account and API tokens, per-day usage history, HWID device lists,
panel plugins, response rules Meridian didn't set, the Remnawave
subscription page, and client IP forwarding (it served the panel's per-user
IP limits).
Web panel
- Meridian runs its own control service in place of Remnawave: no Docker, no
third-party panel, and every server runs a small agent (netagent, static
builds for x86-64 and ARM64) that dials out to it. Nodes open no ports for
management. meridian panelprints the web panel's address and, while it has no owner, a
one-time setup link (--setup-linkresets the owner: new password, sign-in
code off, every device signed out). There is no panel password.- In the panel you manage people, API tokens, privacy levels, the fleet
notice, and the default page language; servers, revisions, and the
subscription title are read-only there. - Person and password forms ask Leave/Stay while edits exist, including
browser back. Person status and usage refresh while visible without
replacing drafts, and actions update the screen they came from and name the
person in their feedback. - Expiry forms edit a native date and time, show the browser zone and the
exact UTC instant, and offer +1 month, +3 months, and No expiry. - QR images export as PNG or SVG with the person's name and fleet title, and
supported browsers copy the PNG. - A closed Individual connections section lists each named connection with
copy and QR actions and the Xray JSON, Mihomo, and sing-box URLs;client show --connectionsprints the same list. - Phone dialogs scroll with sticky actions and 44 px touch targets, and the
panel keeps English and shows a retry notice when a language file fails to
load. - Token creation blocks dismissal while it writes and keeps the one-time secret
in its own step. People and Servers refresh while visible, mark stale data,
and offer retry; background polling no longer keeps an idle owner signed in.
Connection pages and apps
- Connection pages are served by the control service at every person's
subscription URL, including people added in the panel; apps keep receiving
their configs from the same URL. Old UUID links redirect, and a reviewed
apply removes SSH-published page files and retires their service workers. - Owners choose the default language for connection and support pages through
fleet language, the API, or Settings, and can override it per person
(client set --language). The default follows each person's browser; saved
page choices win, and app status messages stay English. - Native subscription status remarks come in English, Russian, Persian, and
Chinese; status codes stay English. - Owners can preview, publish, expire, and clear one fleet notice
(fleet noticeor Settings): apps get it in anannounceheader and pages
show a banner. - Reviewed owner contact (
fleet contact) appears on connection and support
pages in all four languages as a link that opens only when clicked, and
supplies apps' support button. - An app too old for Meridian's connections (v2rayNG before 1.9.17) or no
longer maintained (desktop NekoRay) gets one extra inert entry at the end of
its subscription asking to update or switch to Throne. It is read from that
request's User-Agent only and nothing is stored. - The Not connecting? section explains in all four languages that a red or
"n/a" ping in an app does not mean the connection is broken, how to refresh
the subscription now, and to turn on update-on-launch. - Setup follows your chosen platform and app: labelled store and direct-install
alternatives (including desktop architectures and Linux packages), manual or
one-tap import, and localized Connect steps, with TUN guidance on Clash
desktop apps. Stash joins the additional iOS apps. - Pages show account status, current and lifetime traffic, expiry, and
freshness in all four languages, with a marked offline answer; long
connection lists start with three entries and a "Show all" toggle. - Pages validate configuration and app catalogs before rendering, open setup
even when the optional app catalog stalls, keep quotes in links from breaking
the HTML, offer selectable text when a copy fails, and tell search engines
not to index them. - Xray JSON subscriptions keep Automatic first and add a named profile for each
primary connection, with the same routing and fingerprint alternatives. - Subscriptions accept
/v2ray-json,/stash, and/clashbeside the
existing formats;/sub/<token>/inforeturns account status and links;
profile-update-intervalfollowsdelivery.update_interval_hours(1-168,
default 6);subscription-refill-datecarries the next quota reset. - Empty or unsupported-only subscriptions show inert "No connections available
yet" entries instead of empty documents, duplicate connection names get
stable suffixes, and Xray subscriptions explain when only fingerprint copies
remain. meridian fleet routingreads or reviews the client policy:ru-split
(default) orfull. Private ranges stay direct either way, and Xray JSON
keeps its best-effort BitTorrent direct rule.client previewand Settings explain which format an app's request gets,
which protocols it includes, and which entries are omitted, without showing
credentials.
Control service and agents
- One service (
ctld, runningmeridian serve) keeps users, traffic, and
applied revisions in one SQLite file, serves every subscription format, logs
no requests, and sits behind nginx on a secret path. - Agents enroll over SSH with a single-use token, verify every document the
service signs, and run Xray.meridian applyupgrades an agent in place when
Meridian ships a new build, keeping the node's identity. meridian fleet historylists every reviewed apply the service recorded, with
author, status, and plan hash; the apply lease lives in the service.- API tokens carry read, propose, or approve scopes, or a separate
people
scope for managing people without access to servers, backups, or settings.
Tokens can expire after 1-3650 days (new panel tokens default to 90).
Scoped integrations fetch OpenAPI 3.1 at/api/openapi.json. - Signed node commands are queued durably, delivered only to agents that accept
their kind, executed once even if redelivered, and reported per node. meridian node restart NAMEand the panel's Restart Xray button restart a
node's core and wait for readiness;--allrestarts every managed unit.client removeandclient reissueoffer--cut-offto end existing
sessions once the old credentials are revoked. The confirmation discloses
other people's reconnects, and results distinguish success, fallback
restart, failure, and timeout.client extend NAME --days Nadds time after the later of now and the current
expiry;client addcreates limits, reset period, and device caps together
with the account.client setand the panel keep a private note and one tag per person
(--tag familyis saved asFAMILY);client list --tagfilters.- CLI edits for enable, disable, limits, expiry, resets, and devices accept
people created in the panel, using the same exact-name rules asclient show. client list --attentionand/api/attentionfind people expiring within
seven days, above 80% of their quota, or unused for three days, plus offline
nodes and unhealthy reports; nothing about attention is stored.fleet eventsand/api/eventsgive a local timeline of lifecycle changes,
enforcement, node outages, and token activity, without credentials or client
addresses: up to 2,000 events for up to 180 days.meridian server setrecords monthly bandwidth allowances, reset days,
provider labels, and repeating payment dates, shown byfleet status, server
lists and exports, the panel, and the attention API. Usage is approximate
accepted upload plus download.- Node health reports Xray uptime apart from host uptime, traffic-collection
failures, API failures, memory, disk, and load;fleet statusandcheckflag
unhealthy nodes and treat stale reports as unavailable evidence. - Node totals survive late counter epochs; people show first reported use and
their last reporting node;fleet statusshows who was active in the last
report. - An apply after a Meridian upgrade no longer re-runs every server's package and
hardening baseline; only a change to the baseline or the server's connection
does. meridian fleet upgradecovers the control service, node agents, and Realm.
Aftermeridian updateit moves the service and agents to the new build;
--testedskips GitHub, so Realm stays on the tested version.
Privacy and backups
- Device limits and daily usage history are off by default.
meridian privacy show|setand Settings disclose what each level stores and what a seized
control server reveals; lowering a level deletes its records in the same
transaction, and applies leave privacy settings alone. - Optional daily usage gives per-person and per-server totals per UTC day,
kept 90 days by default (7-730), withclient usage,fleet usage, and
charts in the panel. - Optional device limits use private fingerprints or full details, a fleet
default cap, and per-person overrides (client add|set --devices,client devices --remove|--clear). Apps without a supported HWID header are not
counted, and no client addresses are stored. - Every machine that manages the fleet pulls an encrypted snapshot after each
change, sealed to its own key and to a recovery key shown once at the first
deploy.meridian backup pull,recovery-key,devices, andrevoke
manage them. Snapshots carry people, notes, tags, the notice, language
choices, and privacy settings; private device records clear after a restore. meridian restore --to SERVERrebuilds a lost or seized control server from a
snapshot with a new certificate authority and signing keys, so the old server
signs nothing your nodes accept. Domain links survive once DNS moves;
bare-IP links change and are printed. On a machine with only the snapshot and
the recovery key, restore brings the fleet files back too.
CLI
- The version and beta banner prints once a day and after an upgrade, not before
every command. - Console and CLI quotas use binary GiB and TiB with an explicit Unlimited, and
expiries from 2099 on are refused. - Fleet import reviews name each person's changed creation settings instead of
reporting a reorder. - Restart and cut-off commands report service failures in their JSON error
envelopes, and a failed result read marks the node failed instead of a
retryable timeout.
Docs
- The Russian text of the CLI, web panel, connection and support pages, website,
and docs was rewritten with one glossary. - Hosting, relay, and security guides in all four languages cover October 2026
hosting reports, TLS transfer blocking, mobile whitelist limits, broken
relay-to-exit routes, and an audited account of outbound requests and
download verification. - The website and README show screenshots of the connection page and the web
panel, and/demo/console/is a clickable panel demo beside the connection
page demo, both running on one invented fleet. - The README, website, docs, CLI, web panel, and connection pages say VPN
where they mean the product and call the owner's console the web panel in
all four languages; "proxy" stays only where it is technically exact.
Fixed
meridian applyno longer retries the removal of a deleted server on every
run after an interrupted apply, and an exit whose first apply failed is
cleaned up when you remove it (--forget-unreachablewhen the server is
gone).fleet statusreports pending convergence separately from runtime health
instead of calling a fresh but unapplied configuration healthy.- A second
netagent runexits clearly instead of racing the running agent, and
core starts wait for the Xray API and restore the previous configuration if it
never comes up. - Mihomo, Clash, and Stash subscriptions quote a Reality short ID that looks like
a number (such as12e34567), which those apps read as a float and then
refused the whole document. - API-created IPv6 endpoints produce share links with exactly one pair of
brackets. - Removing a person erases their traffic totals and replay baselines as well as
daily history. client showincludes lifetime traffic and the current period's start, also
when daily history is off.checkreports background enforcement and blob mirror failures with safe error
codes, and a lost token reply keeps its recovery notice.- A server that already ran nginx from nginx.org gets Meridian's sites included,
so certificates and connection pages work there. - Hardening from a security review: the agent re-checks every name that reaches
a file path, an Xray argument, or its API address; the service answers probes
the way nginx does, takes small bodies before sign-in, drops traffic reports
for unknown users, re-checks a node's session before handing it a document, and
keeps its files private.
Removed
- Remnawave, its database, Valkey, the subscription page container, and Docker
on new fleets. - Meridian Studio,
meridian studio, the local Engine behind them, and the
studioinstall extra; the web panel is where fleet management lives.
meridian deploy --json,--events=jsonl,--request, and--dry-runare
unchanged for scripts and agents. meridian panel --show-password(there is no panel password),
deploy --client-ips(the control service does not forward client IPs yet),
andclient show --repair-page(pages are live at the subscription URL).
Compared with 3.x
Read first: this is not an in-place upgrade
- Meridian 4 cannot manage servers deployed by 3.x, and existing client links
cannot carry over. Your 3.x servers keep working. - To keep managing them, stay on 3.x:
uv tool install 'meridian-vpn<4'. - To move: deploy a fresh server with 4.0, give your users the new links, then
meridian teardownthe old server (it also removes 3x-ui). - 3.x and 4.0 cannot share a server, since both need port 443. 4.0 refuses to
deploy onto a server that still runs 3.x (or 2.x) instead of taking it over. - Requires Python 3.11+.
- Both versions fit on one computer — 4.0 keeps its state in
~/.config/meridian(or$XDG_CONFIG_HOME/meridian) and leaves 3.x state in
~/.meridianalone. A fleet set up with a 4.0 beta in~/.meridian-v4or
~/.meridianis found there, so the release manages it without moving files.
Managing people
- Your edits stick — Meridian owns only each person's existence, name, and
squads. Disabling someone (client disableor the web panel), traffic limits,
expiry, notes, and tags survive everyapply. Disabled, limited, or expired
people don't markfleet statusas degraded. - Connect a bot safely — the client guide shows how to give a community bot
its own read-scoped, expiring API token instead of sharing Meridian's
full-access one.
Deploy
- Several fleets on one computer —
meridian context list|use|rename|remove
keeps separate fleets apart, say family and work, kubectl-style:
meridian deploy IP --context workstarts one,--context NAME(before or
after any command) orMERIDIAN_CONTEXTpicks one for a run, and
context usechanges the current one. An existing fleet becomes the
defaultcontext without moving a file; others live incontexts/NAME/
with their own saved servers, sharing Meridian's SSH key. A server belongs
to one fleet at a time,context removedeletes only local files (asking
first while the fleet has servers), andMERIDIAN_HOMEstill pins one fleet. - One command, verified end to end —
meridian deploy IPsets up the control
service and an exit, picks a camouflage target the server can actually use,
pushes real traffic through the delivered subscription, and only then prints
"Done" with a shareable connection page and QR code. Re-running it resumes or
redeploys. - A setup wizard anyone can follow —
meridian setupis a guided,
resumable wizard for one server or many (exits, Realm relays, routing
gateways with failover). It speaks English, Russian, Persian, and Chinese
(asked first, remembered, or--lang), explains each term in one plain
sentence, acceptslocalfor the machine you are on, skips routing questions
unless you have a gateway, suggests five short server names (astra, boba,
foxtrot…), and ends with a plain summary before anything
changes. Runningmeridianalone in a terminal offers to start it.
Choices are arrow-key lists and checklists (Space toggles,?explains,
Esc goes back), typed answers are checked as you enter them, and the
camouflage list leads with sites found in the exit's own network.
MERIDIAN_PLAIN_PROMPTS=1keeps the numbered prompts. - Names in any script —
setupandclient addtake people's names as
typed (Биба, مریم, 王小明); connection pages and output show them, and the
service gets a Latin username (biba). Other client commands accept either. - Review before change —
meridian planshows whatmeridian applywould do
(exit 0 converged, 1 config error, 2 changes pending, 3 evidence unavailable). - Paths — Reality, XHTTP, and Hysteria2 on UDP/443 by default;
--domain
adds WSS (Cloudflare CDN fallback). Blocking Russian destinations stays on
by default (--no-geo-blockto turn it off). - Camouflage next door — without
--sni, a first deploy (andnode add)
scans the server's own subnet and prefers a site whose DNS really points
there and that passes Reality's TLS 1.3 + HTTP/2 check, so the SNI and the
server's IP look like they belong together. VPSes that get a/32address
(Hetzner Cloud and others) scan their surrounding/24. Well-known targets
remain the fallback, and real traffic still decides. - Your own domain as camouflage (self-steal) —
--self-stealondeploy,
node add, andnode snimakes Reality imitate a domain you own, pointed
at the server with a DNS-only record, instead of someone else's site. The
exit gets a Let's Encrypt certificate for the name and answers probes and
unknown SNIs itself with nginx's stock 404, so the name, the certificate,
and the address all match, and no outside site can go down or change under
you. With--domainalone the one domain also keeps XHTTP and WSS working
behind it. Meridian first checks where the name resolves from the server:
it stops when it doesn't resolve and warns when it points elsewhere (a
Cloudflare-proxied record). The wizard offers it as "My own domain", and
test --probeno longer treats a self-steal name as an independent site to
compare against. - Client IPs are never stored — the control service records no client
addresses or connection logs; every TCP connection reaches Xray through nginx
on the server. - TLS fingerprint is a setting — every Reality, XHTTP, and WSS link presents
thechromefingerprint by default (XHTTP and WSS used to send none, which
exposed the client library);--fingerprintor the topology's path
fingerprintswitches it when a region starts flagging one. - Shrink a running fleet —
meridian node removeandmeridian relay remove
edit the topology, show every resource they will delete, and clean up the
node's agent and Xray, Realm units, firewall rules, and published endpoints.
meridian planlists removals too, and the review covers them. - Move an exit to another server —
meridian node replace EXIT SERVER
keeps the exit's ID, Reality keys, protocol paths, SNI, WARP and geo-block
settings, and relays, so clients keep working, then cleans up the old server
through the reviewed apply. The control server can't be moved this way; use
meridian restore. - Forget a server that no longer answers — when a server a change removes
doesn't answer over SSH (blocked from your network, or deleted at the
provider), its cleanup failed on every apply.node replace,node remove,
relay remove, andapplynow offer to forget what was deployed there, or do
it with--forget-unreachable;--yesalone never does. The control service
still deletes what it held, and the server keeps serving the users it had until
you delete or wipe it. - Change a camouflage SNI in one command —
meridian node sni EXIT NEW_SNI
andmeridian relay sni RELAY NEW_SNIswitch an exit or relay to another
site whenmeridian test --probesays the SNI is blocked. They check that
the exit reaches the site over TLS 1.3 with HTTP/2, show the review, and
apply it. The old name is replaced, not kept alongside; apps switch at their
next subscription refresh (every 6 hours) or a manual refresh. They,node add --sni, andrelay add --snirefuse Apple names andwww.microsoft.com. - Edit the fleet as a file —
meridian fleet export > fleet.ymlprints the
topology as YAML with saved server names and no keys, credentials, links, or
transport paths.meridian fleet import fleet.ymlshows each change
(+ client carol,~ exit-2 sni www.example.com -> www.example.org), then
applies the same reviewapplywould; an unedited file is a no-op. Removed
clients go as withclient remove.--dry-runonly shows the changes, and
import refuses unsaved servers and edits that need their own command (moving
an exit or the control server). - Pins stay current between releases — a weekly job opens a pull request
raising the Realm, RealiTLScanner, and acme.sh defaults; the local Xray test
client is pinned by checksum too, and a Realm tarball without a pinned
checksum is refused instead of installed unverified. Relays get Realm's static
build, which runs on any glibc, and a new binary replaces the running one only
after it starts on that server. - One health command:
meridian check— checks whatever the server is in
your fleet: pre-flight readiness for a new server; the control service, each
agent, every compiled port, TLS, and disk for control, exit, and gateway
servers; and each Realm hop for relays. With no server it checks the whole
fleet, and--jsonreturns one typed report.meridian test --probe(short
form:meridian probe) shows a server the way a censor's scanner would.
preflight,rage,node check, andrelay checkare gone: each now stops
with a one-line pointer to the new command (exit 2, or a JSON error envelope
with--json). meridian logs SERVER— shows a server's recent logs without logging in:
the agent and Xray, the control service, and nginx on control, exit, and
gateway servers, and the Realm units on relays.--grep TEXTkeeps matching
lines,--lines Nsets how many, and--componentpicks node, panel, nginx,
or relay. Every line is redacted likemeridian doctor(tokens, keys, UUIDs,
and secret paths), so the output is safe to share.cluster.ymlstops growing with every apply — each apply kept a full copy
of every resource binding, so a small fleet's file passed 300 KB after a few
dozen changes. Older copies of the same remote resource are now dropped when a
change commits; the next apply shrinks existing files.meridian planno longer calls pending changes unavailable — after any
topology edit (even one new client) it listed clients and endpoints as
"observation failed" and exited 3, because their dependencies only get
their new identities during apply. It now shows them asrecheck … after
those dependencies and exits 2, as for any pending change.- "What is blocked?" —
meridian test --probenow tells a blocked server
IP from a blocked camouflage SNI by comparing the server with and without the
SNI against the real camouflage site, and inconclusive stays inconclusive.
It also catches throttling: a ~50 KB download from the control server (and
through the CDN when WSS uses one) that freezes after about 16–24 KB is
flagged with a suggestion to change the IP.meridian checkruns the
download check too when it's run from another machine. meridian testsays how each path fails — every delivered path reports
its time to first byte, and a failed one is reported as "connects, but no
traffic passes" or "unreachable".--jsonaddsdata.transports.meridian testsays what to do about a blocked exit — when nothing on
an exit answers from your network, it prints themeridian node replace
command for that exit (--json:data.recovery). A blocked control server
points to the recovery guide instead, since it can't be moved yet.- Name the server first, like ssh — every server command takes one target:
an IP, a saved name,user@host:port, orlocal.--userand--ssh-port
default to the saved values (elserootand22) everywhere, including
deploy,node add,relay add, andserver add. The old--server NAME
option stops with a pointer to the positional target. relay deployis nowrelay add, matchingnode add,client add, and
server add. The old name stops with a pointer to the new one.- Run Meridian on the server itself — after
meridian deploy local(or on
any saved server whose IP is on this machine), later commands such as
client add,doctor, andnode addrun locally with sudo instead of
SSHing back into the same machine. The same fleet copied to a laptop keeps
using SSH. - Servers that came with only a password — when a server refuses your SSH
keys but accepts a password,meridian deployandmeridian setupask
whether to create a key for Meridian and install it. Say yes, type the
password once (hidden, never saved), and the deploy continues; the key is
saved with the server for later commands. Without a terminal, with--yes,
or with--json, they stop with thessh-copy-idcommand instead. - Per-domain routes on an exit —
meridian route add EXIT --via warp|direct|block VALUES...sends chosen domains,geosite:lists, or
geoip:ranges through Cloudflare WARP, directly, or nowhere, ahead of the
exit's default egress (for example, AI services that block datacenter IPs).
route listandroute removecomplete it; the wizard keeps existing routes. - One route for AI services —
meridian route add EXIT --preset aisends
ChatGPT, Claude, Gemini, Cursor, and the rest of the AI site list through
WARP as one route namedai, so they never see the exit's hosting address
(--via directkeeps them on it). The deploy guide adds what a server route
cannot fix: changing exit countries, device-side leaks, and Google's
country-association request. - Gateway rules can send traffic directly — a routing-gateway rule can
send matching traffic out of the gateway itself instead of to an exit or
pool, so Russian sites can leave from a gateway in Russia. The wizard offers
"directly from the gateway" next to your exits and "nowhere"; in a topology
file it is"action": "direct". The setup summary lists each gateway rule
with where it goes, and existing gateways compile unchanged. - Gateway rules match zones and site lists — a domain rule takes a bare
zone such asru,su, orрф(every site under it), and a new site-list
rule takesgeosite:names such ascategory-ru, the same lists the Xray
JSON and Mihomo subscriptions send directly. Both match the site name, so
the gateway needs no lookup. Exit routes (meridian route add) take zones
too. - Relays look like nothing in particular — nothing a hosting provider can
list on a relay (service, binary, config path, firewall comment) names
Meridian, Realm, a relay, or a VPN. meridian checkmeasures each relay leg — every hop downloads the exit's
camouflage page through the next hop with the clients' SNI and reports
connect time, first byte, and bytes received; a freeze in the 8–32 KB
throttling window suggests moving the relay to another provider.meridian testtests the whole fleet — with no target and several saved
servers it tests every exit and relay entry in turn instead of asking which
one, and exits with the worst result. Each path is named like its
subscription entry ("Reality · Chrome", "XHTTP · Firefox", "Hysteria2 · UDP").- With several exits, subscriptions list the first server's entries ahead of
later ones within each method instead of sorting them by exit name. - A brief network stall no longer fails the apply — every command shared one
SSH connection, so a stall made each later command hang until its own timeout
and the apply stopped. Now SSH notices a silent server within about 15 seconds,
drops the stuck connection, and reconnects. Read-only checks and the control
server's apply record retry for about a minute, and the progress shows
"connection stalled, retrying…". A change whose outcome is unknown is checked
on the server first and is never repeated blindly.
Sharing
- Traffic limits and expiry from the CLI —
meridian client set alice --limit 50GB --reset month --expires 2026-12-31gives a client an
allowance, a reset period, and an end date (--limit noneand
--expires neverlift them);client addtakes the same options, and
client reset-trafficrefills the allowance at once.client showprints
"12.4 GB / 50 GB (resets monthly)" and the expiry,client listgains an
Expires column, and applies leave all of it alone. Sizes are binary
(1 GB = 1024³ bytes), and a bare date lasts to the end of that day, UTC. meridian client reissue NAMEreplaces a leaked link — the client gets a
new subscription ID and new keys, so the old subscription URL, connection
page, and links stop working, and Meridian prints the new links. Status,
limits, and expiry stay, and device registrations are cleared.- Happ, v2rayNG, and other JSON-capable apps get the Xray JSON — with it
comes the automatic failover between entries; they used to get plain base64
links. v2RayTun and Shadowrocket keep links. - Connection names show where traffic exits — entries lead with the exit's
flag and country ("🇩🇪 DE · Reality · Chrome"). Deploy,node add, and the
setup wizard look the country up once from the address's Regional Internet
Registry; set--countrywhen it is wrong (anycast or leased ranges). - A redesigned connection page — two clear steps (install an app, add the
connection with one tap), the subscription QR beside them on a computer for
setting up a phone, and everything else folded into quiet panels: every
individual connection with Open, Copy, and QR, "Not connecting?" tips with
the self-check, and the router guide. Russian pages no longer rename the
first connection "Основной", andmeridian dev previewshows a realistic
page. Without--display-name, the header names the exit countries
("🇩🇪 Germany · 🇳🇱 Netherlands") in the page's language. - A WebRTC leak tip on the connection page — "Not connecting?" now says that
an app running as a proxy only can let websites in a browser see the real IP
address, and to turn on the app's VPN (TUN) mode. Shown in English, Russian,
Persian, and Chinese, with no external links. - Connection pages are built from each user's real subscription, so relays and
every enabled protocol appear. Subscription links live under the
connection-page path and never reveal the web panel's address. - Apps refresh subscriptions every 6 hours — every subscription sends
profile-update-interval, so Happ, Clash Verge, and other apps that read it
pick up new exits and relays within hours. meridian client add|show|list|set|reset-traffic|remove|enable|disable.
client removedeletes the user and their page; links stop working
immediately.- Connection pages recommend apps per platform — Happ first, then
FlClashX and Clash Mi (plus Throne on desktop), with a link to the router
guide and a note on subscription refresh and app updates. v2rayNG and
Streisand import links are fixed, Throne import is added, and the broken
v2rayN button is gone. App icons ship once in a shared cached file, so
each page loads about 70 KB less. - "Check my connection" — the page tests the device clock, whether data
keeps flowing (the throttling freeze), and the subscription from the
visitor's own network, then copies a report without links or secrets that
they can send you. - Every deploy offers every method — without a domain, XHTTP
and Hysteria2 now run on the server's IP address (Let's Encrypt certifies
IPs), next to Reality, so a block on one method leaves the others. A domain
carries XHTTP and adds WebSocket through the Cloudflare CDN. Hysteria2 is on
by default (--no-hysteria2turns it off), and the wizard only asks for an
optional domain instead of a list of backup methods. - Hysteria2 is disguised — its UDP traffic is wrapped in salamander
obfuscation, so censors see random packets instead of QUIC with a readable
server name. Every subscription format carries the setting automatically. - Entries have readable names — apps show "Reality · Chrome", "XHTTP ·
Firefox", "WebSocket · CDN", or "Hysteria2 · UDP" (plus the exit's name when
you have several, and "via relay" for relay entries) instead of internal IDs. - Every direct TLS method comes in two fingerprints — Reality and XHTTP
are offered with both a Chrome and a Firefox TLS fingerprint, so if
censors block one fingerprint, the other entry keeps working. Automatic
switching never mixes the two: Russian filtering reportedly stretches a
2-minute freeze to 10 minutes when a new fingerprint arrives during it.
Xray JSON apps get a separate "Automatic · Firefox" entry, Mihomo apps can
pick the copies by hand, and sing-box apps (which can't keep them out of
automatic switching) don't get them. - Russian sites work with the VPN on — Xray JSON and Mihomo subscriptions
send local-network,.ru/.su/.рф,geosite:category-ru, andgeoip:ru
traffic directly and refuse foreign QUIC, while the exit's block stays as a
safety net. Plain Base64 imports still need the app's own routing settings. - Torrents skip the VPN in Xray apps — Xray JSON subscriptions send
recognized BitTorrent peer connections directly from the device, so a torrent
client left running doesn't draw abuse complaints against the exit.
Encrypted peers and UDP DHT/uTP may still use the tunnel; Mihomo, sing-box, and
Base64 subscriptions are unchanged. - sing-box apps get a Meridian profile — sing-box-based apps (SFA, SFI,
Karing) pick the fastest working entry automatically, can still choose one
by hand, and send local-network and.ru/.su/.рфsites directly. Nothing
is downloaded at startup, so the app starts even when GitHub is blocked.
sing-box has no XHTTP, so those entries are left out.
Docs and agents
- Reviewed translations — the Russian, Persian, and Chinese CLI, docs, and
connection pages were reviewed against the English source: mistranslations,
machine-translation leftovers, and stray tokens fixed, one term per concept
in each language, and docs claims checked against the code. - An agent guide —
meridian help agentsprints a Markdown guide that
explains how Meridian works and how to drive it safely: non-interactive
flags, JSON envelopes, plan before apply, exit codes, and which outputs are
secrets.meridian help COMMANDshows any command's help, git-style. - Docs for people and agents — getmeridian.org's docs have search, a
per-page table of contents, and proper right-to-left Persian. Every page is
also served as Markdown (add.mdto its address), with Copy page and Open
in ChatGPT or Claude buttons, and/llms.txtindexes it all. Old/docs/...
links redirect. - A page for the people you share with — the docs' new Connecting page
walks a recipient through installing an app, adding the link, turning on
VPN (TUN) mode, and what to do when it stops working; send it along with
the link. - Lighter docs pages — diagrams arrive as images that follow the light or
dark theme instead of ~3 MB of JavaScript, and docs pages prefetch a link
only when you point at it instead of every page in the sidebar. - A lighter, readable website — the home page is fully translated into
Russian, Persian, and Chinese and works without JavaScript (Tor Browser's
Safest mode included); choosing English sticks. Fonts download about 70%
less, text meets WCAG AA contrast in light and dark themes, link previews
load in messengers, and the blog has an RSS feed at/blog/rss.xml. The
command builder only offers commands and flags the CLI actually has.
Security and correctness
meridian testtrusts valid certificates on macOS — uv's bundled Python
looked for root certificates at a Linux path, so every Let's Encrypt
certificate was reported untrusted; certificate checks now use certifi.- Starts with current Typer — Typer 0.26 stopped installing Click, and a
fresh install of an earlier beta failed at launch withNo module named 'click'. Meridian now needs Typer 0.26 or later and uses the Click it ships. - The installer can be verified — every release attaches
install.shand
itsSHA256SUMS, the installation guide shows how to check them, and the
script pins uv's installer by version and SHA-256 instead of piping the
latest one into a shell.MERIDIAN_VERSION=4.0.0installs one exact release. - Servers look like ordinary hosts — units and directories don't name the
proxy software: the control service isctldin/opt/ctld, the agent is
netagent, and its Xray isnetcore, like relays'netfwd.meridian check
andmeridian doctorname the role behind each unit, andmeridian teardown
removes them. - Exits look up destinations over encrypted DNS only — the exit's direct
egress used the host's resolver, so the hosting provider saw every site its
users opened in plain-text DNS, and a failed encrypted lookup fell back to
plain8.8.8.8. Exits now resolve every name over DNS over HTTPS, asking
Cloudflare, Quad9, and Google at once (each reached by IP address on IPv4 or
IPv6), and never fall back to plain DNS: if none answers, sites by
name fail through that server, andmeridian checkreports a resolver the
server cannot reach. The system lab sniffs an exit during proxied traffic and
requires no plain DNS question on the wire. - Large uploads over XHTTP never hit nginx's body limit — nginx's 1 MB
default cut long uploads off on 3.x when a client chose a streaming XHTTP
mode. 4.0 serves packet-up only and now also lifts the limit. - Removing or moving an exit cleans up its certificate — the acme.sh
renewal, the certificate files, and (with the server's last certificate)
the port-80 challenge listener go, instead of renewing forever. - A relay with its own camouflage site really imitates it —
relay add --snigave clients the new name while the exit answered probes with its own
site's certificate (awww.google.comcertificate foryandex.ru), which
gives the relay away. Each relay name now gets its own Reality listener on
the exit, and anything else sent through the relay reaches that site. - Debian 12 and 13 deploy — on Debian 12, fail2ban found no SSH log file and
stopped right after starting; it now reads the system journal on every
supported release, and a package Debian only remembers is no longer mistaken
for an installed one. Stock Debian 13 deploys and joins as an exit too: the
baseline no longer waits for adnsutilspackage Debian stopped shipping. node replacemoves a bare-IP exit's certificate address — the moved
exit kept the old server's IP as its XHTTP and Hysteria2 certificate name,
so the new server could never get a certificate and the move failed. If a
move already failed that way, rerun the samemeridian node replace.node add NAMEkeeps the saved name — adding a saved server without
--nameresaved it under its IP, so the name stopped working; it now keeps
the name and uses it for the exit too.meridian test NAMEandmeridian probe NAMEtake saved names — a name
without a dot was refused as "not a full domain name".- Certificate failures say why — the error kept acme.sh's first lines
(timestamps and progress) and cut off its reason; it now shows the last ones. - Unknown geo lists are refused at review — a gateway rule or exit override
naming ageosite:/geoip:list or country the servers' Xray data lacks made
Xray refuse its whole config, so the server stopped converging. Review now
stops with the name and a close match (categry-ru→category-ru), and a
saved fleet with such a name still loads so the rule can be removed. - Re-running a command resumes it —
relay addfor a relay that is already
declared finishes it instead of failing on a duplicate listener, and a bare
meridian testafter removing servers tests what is left instead of asking
which saved server to use. - Page branding is checked before anything changes — an unknown
--color
or an--iconthat is neither an emoji nor a reachable image stops deploy
with the valid choices; a redeploy that names only some branding flags keeps
the rest. - No request logging on Meridian's web server; the live SSH port is never
firewalled; teardown removes everything Meridian created and nothing it
didn't: fail2ban stays on, and nginx keeps running when it serves your own
sites, as do your own HAProxy/Caddy. - Deploy checks the loopback ports its nginx serves the control service on
(8443 and 8444) before changing anything, and names the process holding one,
instead of failing halfway through onnginx -t. - An out-of-date copy of
cluster.ymlcan't undo newer changes. The control
server records the last change applied, andapplyrefuses to run from an
older copy or while another machine is applying. - Mihomo-based apps (FlClash, Clash Verge, ClashMi) and sing-box routers
connect again. Recent Xray releases reject clients that announce a version
below the server's minimum, and those apps announce 1.8.x, so their Reality
connections failed with "authentication failed". Exits now accept any client
that speaks Reality. - Setup no longer opens an untagged
443/udpfirewall rule, and the next apply
removes the one earlier v4 builds left. - Web panel and connection-page links typed or copied without the trailing slash
now open; they used to redirect to an internal port and fail. - Subscriptions list Reality first, then XHTTP, WSS, and Hysteria2 last. Apps
use the first entry by default, and Hysteria2 (UDP, often blocked) used to
lead. sing-box and Stash no longer show a duplicate "automatic fallback"
server. - XHTTP links work. Apps sending the default
chromefingerprint speak
HTTP/2, and the server answered in HTTP/1.1, so no traffic passed. - A fresh deploy with Hysteria2 converges. Xray started before its certificate
existed, so it refused to run and the deploy stopped. - Servers without apt (CentOS, Fedora, Alpine) are refused by name before
anything changes, instead of failing halfway at "apt-get: command not found";
meridian checkreports them as a failure rather than a warning. - Reality keys are generated on your machine, so a fresh exit needs neither
unzipnor an unverified Xray download to create them. - Adding or removing an exit renames existing subscription entries instead of
leaving the old ones behind. Before, every entry appeared twice, and a stale
Firefox copy slipped into the automatic failover group. meridian checkandmeridian testare fail-closed: skipped evidence is never
reported as a pass.- Mihomo and sing-box subscriptions are tested with the real engines, not only
parsed: every change runsmihomo -t(Mihomo 1.19.32) andsing-box check
(sing-box 1.14.3) on what the control service delivers. The client-management
docs list the tested apps and engine versions. - Downloaded binaries (Xray, Realm, RealiTLScanner) are checksum-verified, so a
re-pushed release cannot change what a fresh server runs. meridian updatestays on the current major version;--majormoves to the
next one after you have read its release notes.
Tested versions
Fresh deploys install the versions below. meridian fleet upgrade moves Realm
to its newest release in the same major without a Meridian update (--tested
keeps the version below), and the choice is saved for later applies.
| Component | Version |
|---|---|
| Xray-core (exits, gateways, test client) | 26.7.28
|
| Realm (relay forwarder) | 2.9.6
|
RealiTLScanner (meridian scan)
| 0.2.3
|
| acme.sh (certificates) | 3.1.6
|
Not yet available
- Client IP forwarding and per-user IP limits: the control service stores no
client addresses. A fleet moved bymeridian migrateloses it. - Moving the control server with
meridian node replace; rebuild it from a
snapshot withmeridian restore.
Removed
- 3x-ui, HAProxy and Caddy support; per-server
proxy.ymlcredentials. - The website's ping page: a browser cannot tell a blocked server from one that
refuses the connection. Runmeridian test --probefrom the censored network,
or open your connection page there. meridian fleet recover,apply --parallel/--prune-extras, and the
desired_*lists incluster.yml.