Guards and mockups only, ahead of the pages (inbound-antispam-panel
6/12). The owner agreed the feature ("Следующая по дорожной карте -
inbound-antispam-panel" / "Да", 2026-10-11) and started this step
("Начинай"), so the two screens are no longer "drawn but not built":
- guard_panel_test.go: in-log and in-filter-lists removed from
deferredScreens. From here TestLegacyRatchetMatchesTheEngine wants
the engine to have both pages - red until the next commit.
- guard_routes_test.go: the four routes join routes.inbound, so they
must exist with the relay on and answer 404 with it off.
Two mockup details brought to what the kit can draw, found when the
pages were built from it:
- help: the two new topics are one paragraph with a break in it, as
every topic is (panel.css has no gap between paragraphs of a topic);
- in-filter-lists: the directory in "Files" is mono at the text size -
the kit's inline code has no small variant.
check.py: 32 screens, 0 violations; outlines.json unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
158 lines
21 KiB
HTML
158 lines
21 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en" data-theme="light">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Help · SelfPost</title>
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.min.css">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@3/dist/tabler-icons.min.css">
|
||
<link rel="stylesheet" href="../shared/brand.css">
|
||
<link rel="stylesheet" href="theme.css">
|
||
</head>
|
||
<body>
|
||
<nav class="navbar is-primary" aria-label="main navigation">
|
||
<div class="container">
|
||
<div class="navbar-brand"><a class="navbar-item" href="overview.html"><img src="../../selfpost-wordmark.svg" alt="SelfPost"></a></div>
|
||
<div class="navbar-menu is-active">
|
||
<div class="navbar-start">
|
||
<a class="navbar-item" href="overview.html">Overview</a>
|
||
<div class="navbar-item has-dropdown is-hoverable">
|
||
<a class="navbar-link" href="out-domains.html">Outbound</a>
|
||
<div class="navbar-dropdown">
|
||
<a class="navbar-item" href="out-domains.html"><i class="ti ti-world-upload"></i>Domains</a>
|
||
<a class="navbar-item" href="out-log.html"><i class="ti ti-list-details"></i>Log</a>
|
||
<a class="navbar-item" href="out-queue.html"><i class="ti ti-stack-2"></i>Queue</a>
|
||
<a class="navbar-item" href="dmarc.html"><i class="ti ti-report-analytics"></i>DMARC reports</a>
|
||
</div>
|
||
</div>
|
||
<div class="navbar-item has-dropdown is-hoverable">
|
||
<a class="navbar-link" href="in-domains.html">Inbound</a>
|
||
<div class="navbar-dropdown">
|
||
<a class="navbar-item" href="in-domains.html"><i class="ti ti-world-download"></i>Domains</a>
|
||
<a class="navbar-item" href="in-log.html"><i class="ti ti-list-details"></i>Log</a>
|
||
<a class="navbar-item" href="in-queue.html"><i class="ti ti-stack-2"></i>Queue</a>
|
||
<a class="navbar-item" href="in-quarantine.html"><i class="ti ti-mail-pause"></i>Quarantine</a>
|
||
<a class="navbar-item" href="in-filter-lists.html"><i class="ti ti-filter"></i>Filter lists</a>
|
||
</div>
|
||
</div>
|
||
<div class="navbar-item has-dropdown is-hoverable">
|
||
<a class="navbar-link" href="health.html">Server</a>
|
||
<div class="navbar-dropdown">
|
||
<a class="navbar-item" href="health.html"><i class="ti ti-heartbeat"></i>Health</a>
|
||
<a class="navbar-item" href="preflight.html"><i class="ti ti-checklist"></i>Preflight</a>
|
||
<a class="navbar-item" href="system-log.html"><i class="ti ti-file-text"></i>System log</a>
|
||
<a class="navbar-item" href="backup.html"><i class="ti ti-archive"></i>Backup</a>
|
||
<a class="navbar-item" href="users.html"><i class="ti ti-users"></i>Users</a>
|
||
<a class="navbar-item" href="settings.html"><i class="ti ti-settings"></i>Settings</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="navbar-end">
|
||
<div class="navbar-item has-dropdown is-hoverable sp-current">
|
||
<a class="navbar-link" href="account.html"><i class="ti ti-user-circle"></i>admin</a>
|
||
<div class="navbar-dropdown is-right">
|
||
<a class="navbar-item" href="account.html"><i class="ti ti-key"></i>Account</a>
|
||
<a class="navbar-item" href="help.html"><i class="ti ti-help"></i>Help</a>
|
||
<hr class="navbar-divider">
|
||
<form method="post" action="login.html"><button type="submit" class="navbar-item"><i class="ti ti-logout"></i>Sign out</button></form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
<div class="sp-perf" aria-hidden="true"></div>
|
||
|
||
<main>
|
||
<div class="container sp-page">
|
||
<div class="sp-head">
|
||
<div class="sp-grow">
|
||
<p class="sp-kicker">Reference</p>
|
||
<h1 class="title is-3">Help</h1>
|
||
<p class="sp-lead">What each screen checks or does, and what to do when it is not green. The ? in a box's head opens its topic here.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="columns">
|
||
<div class="column is-3">
|
||
<aside class="menu sp-side">
|
||
<p class="menu-label">Overview</p>
|
||
<ul class="menu-list">
|
||
<li><a class="is-active" href="#checks"><i class="ti ti-activity-heartbeat"></i>Health checks</a></li>
|
||
<li><a href="#certificate"><i class="ti ti-certificate"></i>TLS certificate</a></li>
|
||
<li><a href="#rdns"><i class="ti ti-arrows-exchange"></i>Reverse DNS</a></li>
|
||
</ul>
|
||
<p class="menu-label">Outbound</p>
|
||
<ul class="menu-list">
|
||
<li><a href="#dns"><i class="ti ti-world-check"></i>DNS records</a></li>
|
||
<li><a href="#apps"><i class="ti ti-apps"></i>Applications</a></li>
|
||
<li><a href="#limits"><i class="ti ti-gauge"></i>Rate limits</a></li>
|
||
<li><a href="#log"><i class="ti ti-list-details"></i>Outbound log</a></li>
|
||
<li><a href="#queue"><i class="ti ti-stack-2"></i>Queue and retries</a></li>
|
||
<li><a href="#dmarc"><i class="ti ti-report-analytics"></i>DMARC reports</a></li>
|
||
</ul>
|
||
<p class="menu-label">Inbound</p>
|
||
<ul class="menu-list">
|
||
<li><a href="#inbound"><i class="ti ti-inbox"></i>Backup-MX and forwarding</a></li>
|
||
<li><a href="#upstream"><i class="ti ti-arrow-forward-up"></i>Upstream</a></li>
|
||
<li><a href="#recipients"><i class="ti ti-address-book"></i>Valid recipients</a></li>
|
||
<li><a href="#filter"><i class="ti ti-shield-check"></i>Spam filter</a></li>
|
||
<li><a href="#inbound-log"><i class="ti ti-list-details"></i>Inbound log</a></li>
|
||
<li><a href="#filter-lists"><i class="ti ti-filter"></i>Filter lists</a></li>
|
||
</ul>
|
||
<p class="menu-label">Server</p>
|
||
<ul class="menu-list">
|
||
<li><a href="#backup"><i class="ti ti-archive"></i>Backup and moving a domain</a></li>
|
||
<li><a href="#users"><i class="ti ti-users"></i>Users and roles</a></li>
|
||
<li><a href="#settings"><i class="ti ti-settings"></i>Settings</a></li>
|
||
</ul>
|
||
<p class="menu-label">Account</p>
|
||
<ul class="menu-list">
|
||
<li><a href="#account"><i class="ti ti-user-circle"></i>Your account</a></li>
|
||
</ul>
|
||
</aside>
|
||
</div>
|
||
<div class="column is-9">
|
||
<div class="box">
|
||
<div class="sp-box-head"><span class="sp-no">01</span><h2>Overview</h2></div>
|
||
<div class="sp-help-topic" id="checks"><h3>Health checks</h3><p>Six checks, and the worst of them is the postmark. <span class="tag is-success is-light">ok</span> needs nothing; <span class="tag is-warning is-light">warn</span> still delivers mail but will stop doing so if ignored; <span class="tag is-danger is-light">fail</span> means mail is being lost or refused now. <a href="health.html">Health</a> shows the readings behind them: CPU and memory are the container's own, not the host's spare capacity, and network is a short window, not a daily total.</p></div>
|
||
<div class="sp-help-topic" id="certificate"><h3>TLS certificate</h3><p>The certificate Postfix presents on 465 and 587. The reverse proxy or the image mounts it, the panel does not issue it. It warns 14 days before expiry and fails once expired, or when the file is missing or unreadable — clients that verify certificates then refuse to connect.</p></div>
|
||
<div class="sp-help-topic" id="rdns"><h3>Hostname and reverse DNS</h3><p>The hostname (<code>SELFPOST_HOSTNAME</code>) must resolve to this server's address, and that address must resolve back to the hostname. Large receivers reject or spam-folder mail from hosts where the two disagree. The PTR record is set at your hosting provider, not in your DNS zone.</p></div>
|
||
</div>
|
||
<div class="box">
|
||
<div class="sp-box-head"><span class="sp-no">02</span><h2>Outbound</h2></div>
|
||
<div class="sp-help-topic" id="dns"><h3>DNS records</h3><p>DKIM proves the message was signed by this relay, SPF lists the addresses allowed to send for the domain, DMARC tells receivers what to do when both fail and where to report. Publish all three exactly as shown; merge SPF into an existing record rather than adding a second one. A domain's status is the worst of its three records, and results are cached for a few minutes, so use Re-check DNS after publishing. The SPF check is shallow: it looks for this server's address in the record itself and does not follow <code>include:</code> or <code>redirect=</code>, so a record that relies on them is reported as a warning, not a failure. <code>p=none</code> does not affect delivery; tighten to <code>quarantine</code>, then <code>reject</code>, once the reports look clean. A domain's report address is set in its Domain settings.</p></div>
|
||
<div class="sp-help-topic" id="apps"><h3>Applications</h3><p>An application is one SASL login, unique across all domains. It may send as any address of its domain or only as listed addresses, and, with a list of client IPs set, only from those addresses. The password is shown once at creation or regeneration and is not stored in readable form.</p></div>
|
||
<div class="sp-help-topic" id="limits"><h3>Rate limits</h3><p>Level 1 is a per-IP ceiling set in <code>.env</code>. Level 2 is optional, per domain and per application, entered by hand or computed from the last 30 days of sending, and can never exceed level 1. An application's own limit replaces its domain's.</p></div>
|
||
<div class="sp-help-topic" id="log"><h3>Outbound log</h3><p>One row per message and recipient, with the status Postfix last reported: queued (accepted, nothing reported yet), sent (the receiving server took it; what the mailbox does next is not reported back), deferred (not taken yet, Postfix tries again), bounced (failed for good, or the queue lifetime ran out) and rejected (refused before queueing under a level-2 rate limit, so it never reached Postfix). A message's page lists these steps and the lines Postfix wrote about it in <code>mail.log</code>, found by queue id; that file is rotated daily and about two weeks are kept, so an old message may show none. Rows are deleted after the retention set in Server › Settings, 90 days by default. A domain administrator sees only the rows of their own domains.</p></div>
|
||
<div class="sp-help-topic" id="queue"><h3>Queue and retries</h3><p>The page lists, as <code>postqueue -p</code> prints it, the messages Postfix has accepted and not yet delivered: mail being sent right now and mail deferred for a later attempt. Only the global role can open it, and it only shows; nothing here deletes or forces a message. A deferred message is tried again after the first retry delay, then at gaps that double up to a cap, until the receiving server takes it or the queue lifetime runs out and it bounces; there is no attempt counter, and the box on the page shows this server's values. A queue that keeps growing means a receiver is refusing or not answering: open the message from the Outbound log to read the reason Postfix logged.</p></div>
|
||
<div class="sp-help-topic" id="dmarc"><h3>DMARC reports</h3><p>An aggregate report is the summary a receiving provider sends, usually daily, to the <code>rua=</code> address of your DMARC record: which servers sent mail as your domain and whether SPF or DKIM passed for it. A domain's report address is one of three choices, set in its Domain settings: no reports (the default for a new domain), the SelfPost hosted address (an address on this server whose reports are parsed and shown under DMARC reports; offered only while hosted reports are enabled on the server), or an address typed for the domain (an ordinary mailbox that receives the raw XML; a button fills in your own profile e-mail). When the typed address is on another domain than the one sending, that domain must publish a report-authorization record, or providers will not send; the domain's page shows it with the other DNS records and checks it. In the tables pass means SPF or DKIM passed and aligned, fail means neither did, and your own server shows as <em>this relay</em>. A fail from any other source is someone else sending as your domain — a forwarder, an application you forgot, or abuse — so do not tighten <code>p=</code> until that sender is fixed or removed. A domain administrator reads the reports of their own domains.</p></div>
|
||
</div>
|
||
<div class="box">
|
||
<div class="sp-box-head"><span class="sp-no">03</span><h2>Inbound</h2></div>
|
||
<div class="sp-help-topic" id="inbound"><h3>Backup-MX and forwarding</h3><p>An optional backup-MX or forwarder, switched on in the server's <code>.env</code>; the Inbound menu exists only then. Postfix accepts mail on port 25 for the listed domains only and hands each message on to that domain's upstream; there are no mailboxes. For each domain publish the MX record its page shows, and keep a primary MX the domain already has if this is a backup. The MX tag is green when at least one MX of the domain points at this server, and a domain accepts no mail until an upstream is saved on its page. Adding and deleting domains is for the global role.</p></div>
|
||
<div class="sp-help-topic" id="upstream"><h3>Upstream</h3><p>The upstream is the server that actually holds the mailboxes. Give its host and port — used exactly as written, with no MX lookup — and choose the TLS for the hop to it: Opportunistic uses TLS when the upstream offers it and otherwise sends in the clear, Required holds the mail until a TLS session is possible, Off never uses TLS. While the upstream does not answer, Postfix keeps the mail and retries as for any other mail.</p></div>
|
||
<div class="sp-help-topic" id="recipients"><h3>Valid recipients</h3><p>Choose whom this domain accepts. Listed addresses only: the relay accepts exactly the addresses you list, one per line or comma-separated, and refuses any other while the sender is still connected, so it never has to send a bounce for them. Any recipient: everything at the domain is accepted and passed on, and an address the upstream then rejects comes back as a bounce from this server to a sender who is often forged — backscatter. Prefer a list, and keep it in step with the mailboxes upstream.</p></div>
|
||
<div class="sp-help-topic" id="filter"><h3>Spam filter</h3><p>The spam filter belongs to the server, not to a domain. The server's administrator attaches it in the server's <code>.env</code>, and from then on every inbound domain is screened by it before mail is handed on; the box shows on or off and has nothing to switch. Off means mail goes to the upstream unfiltered. While the filter is down, mail is either accepted unfiltered (the default) or deferred, so the sending server tries again later, as the server's setting says; the box states which.</p></div>
|
||
<div class="sp-help-topic" id="inbound-log"><h3>Inbound log</h3><p>One row per recipient of a message offered on port 25 for an inbound domain, with what was decided: <span class="tag is-success is-light">accept</span> — handed on to the upstream; <span class="tag is-danger is-light">reject</span> — refused for good; <span class="tag is-warning is-light">tempfail</span> — the sender was asked to come back later; <span class="tag is-primary is-light">quarantine</span> — held by the filter. <em>Why</em> names who decided. <code>rspamd</code> is the spam filter, with its action, the score against the reject threshold and the heaviest symbols; <code>postfix</code> is the relay's own rule — an unknown recipient, a sender domain that does not exist — with its reply; <code>selfpost</code> means nobody judged the message: it was relayed with no filter attached. Accept says what this server did, not what the upstream did with the message afterwards.<br><br>Accepted mail is recorded as it passes; refused mail is read from <code>mail.log</code>, so its row has no subject, and a message refused after its text was sent is one row however many recipients it had. A refusal to relay for a domain that is not an inbound one is every scanner on the internet and is not recorded. Rows are kept for the number of days set in Settings, and never more than 10 000.</p></div>
|
||
<div class="sp-help-topic" id="filter-lists"><h3>Filter lists</h3><p>Two lists for the whole server that correct the spam filter by hand. An entry is a sender address, a sender domain — that domain, not its subdomains — or a client address or network in CIDR form. A sender on the Deny list is refused outright. A sender on the Allow list is given a weight no spam score outweighs, so the filter lets it through. When entries of both lists match one message, <strong>Deny wins</strong>.<br><br>SelfPost does not apply the lists itself: it writes them as files under <code>/data/antispam/</code>, and rspamd rereads a file within seconds of a change. With the spam filter off the lists are kept and can be edited, but nothing reads them. The sender matched is the envelope sender — the one in the log — not the From line a mail program shows.</p></div>
|
||
</div>
|
||
<div class="box">
|
||
<div class="sp-box-head"><span class="sp-no">04</span><h2>Server</h2></div>
|
||
<div class="sp-help-topic" id="backup"><h3>Backup and moving a domain</h3><p>Full backup downloads one archive of the whole instance: <code>data/</code> (the database, DKIM keys and application credentials), <code>docker-compose.yml</code>, <code>.env</code> and <code>certs/</code>. The Postfix queue is not in it. The backup is taken while the server is running, and Postfix keeps moving messages through the queue, so a copy could hold a message twice or miss it; mail still waiting for delivery is therefore not carried over, and a restored server starts with an empty queue. To keep the queue, stop the container and archive the project directory instead. The private key in <code>certs/</code> has to be readable by the panel: give it to group 998 on the host (<code>chgrp 998</code>, <code>chmod 640</code>). Until then the panel refuses to make a backup and names the file, rather than hand over an archive without the key. It holds secrets, so leave Encrypt with a password ticked: the file is sealed as <code>.spbk</code>, the password is not stored, and without it nothing can be recovered. To restore, unpack it into an empty project directory (decrypt a <code>.spbk</code> first with <code>selfpost-backup -decrypt</code>) and start the same SelfPost version that made it; the panel refuses data from another version. The reverse-proxy configuration and <code>mail.log</code> are not included. One domain moves on its own: Export domain on its settings page writes a <code>.json</code> (or encrypted <code>.spde</code>) with its DKIM key and its applications' passwords, and Import a domain here reads it into another instance, so the published DNS needs no change.</p></div>
|
||
<div class="sp-help-topic" id="users"><h3>Users and roles</h3><p>The two roles are a reach, not a rank: every user is an administrator and signs in with a username and password. Global reaches the whole server — Overview, Server, the queue and every domain — and is the only role that adds or deletes domains and users. Domain reaches only the domains assigned to it, outbound and inbound separately (the same name on both lists is two assignments); <em>All</em> includes domains added later, and a domain user needs at least one domain or <em>All</em> on either list. The only global user cannot be demoted or deleted, and you cannot delete the account you are signed in with. A new password set here signs that user out of their other sessions.</p></div>
|
||
<div class="sp-help-topic" id="settings"><h3>Settings</h3><p>Settings holds what is true of the whole instance. Log retention is how many days the Outbound log keeps its rows, from 7 to 365 and 90 by default; a sweep every six hours deletes older ones, and it is the main driver of how fast <code>/data</code> grows. With the inbound relay on there is a second number, for the Inbound log, with the same range. It does not change the rotation of <code>mail.log</code>, which is daily with about two weeks kept. The sending rate limit shown under it is level 1, the per-client-IP ceiling set in <code>.env</code>: changing it needs a restart, and no level-2 limit can exceed it.</p></div>
|
||
</div>
|
||
<div class="box">
|
||
<div class="sp-box-head"><span class="sp-no">05</span><h2>Account</h2></div>
|
||
<div class="sp-help-topic" id="account"><h3>Your account</h3><p>Account is your own, whatever your role: your username and e-mail, and your password. Changing the password signs out every other session of this account and keeps the one you are using; applications have their own logins and are not affected.</p></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<footer class="sp-foot">SelfPost 1.8.0 · © 2026 Mix · <a href="#">License (AGPL-3.0)</a> · <a href="#">Source</a> · No warranty</footer>
|
||
</div>
|
||
</main>
|
||
</body>
|
||
</html>
|