-
Notifications
You must be signed in to change notification settings - Fork 3
Installing on Linux
Released in 6.3.0, on 10 September 2026 - the first release in this server's history to carry Linux packages, and the reason that number is 6.3 and not 6.2.29. The
.deb, the.rpmand the AppImage on the release page are built for x86-64 and AArch64 by the tag's own workflow; building from source is still documented below, but it is no longer the only way in.hMailServer runs on Linux, on x86-64 and AArch64, since the work of 8 September 2026. This page says exactly how far that goes: what is packaged, what is proven, what is not there yet, and how a Linux installation is administered without a Control Panel. Every claim on it was checked against the tree that day; the Linux and AArch64 section of the roadmap is the running record of the rows still open, and the packaging README is the file this page is drawn from.
Read this first. The Linux build is the server: the same SMTP, POP3, IMAP,
delivery, anti-spam and REST code as the Windows service, compiled with clang or
GCC from one CMakeLists.txt. It is not the Control Panel, which is a Windows
application, and it has no COM, which is the surface every Windows setup tool
uses. Administration on Linux is the configuration file, the server's own
command-line options, and the REST API, which creates domains and accounts. If you need the Control Panel, you need
Windows, or a Windows machine that reaches the Linux server's REST listener.
flowchart LR
subgraph win["Windows"]
CP["Control Panel"] -- COM --> WS["hMailServer.exe<br/>(service)"]
end
subgraph lin["Linux"]
INI["/etc/hmailserver/hMailServer.ini"] --> LS["/usr/bin/hmailserver<br/>(systemd unit)"]
CLI["hmailserver --set-admin-password<br/>--create-database / --upgrade-database"] --> LS
REST["REST API :8045<br/>(and the Control Deck)"] --> LS
LS --> DB[("PostgreSQL or MySQL/MariaDB")]
LS --> STORE["/var/lib/hmailserver"]
end
- What is proven
- What you get
- Installing the package
- First start, step by step
- The server's command line
- Where things are
- Administering it
- Logs and the journal
- Upgrading
- What is not there yet
- Building it yourself
On 8 September 2026, against a live PostgreSQL 18:
| Step | Result |
|---|---|
hmailserver --create-database |
Created the database and built the schema (version 6031) from the create script |
hmailserver --upgrade-database |
Reported nothing to do |
systemctl start (the unit runs --foreground) |
The server started and opened its SMTP, POP3, IMAP and REST listeners |
POST /api/v1/domains/{domain}/accounts |
Created an account |
SMTP submission with AUTH
|
Accepted, delivered to the mailbox on disk |
IMAP SELECT INBOX / FETCH
|
The same message, subject intact |
Both architectures compile every one of the 496 core translation units (x86-64
natively, AArch64 cross-compiled); the .deb was installed on a machine, created
the service user and directories with the stated modes, and its binary read the
packaged configuration. The AArch64 packages are built by CI on an ARM runner
and have not yet been installed on ARM hardware by hand; the roadmap says so.
One release carries every platform's artefact at one version. For a tag
vX.Y.Z the release page holds, beside the Windows installer:
| Artefact | For | Name |
|---|---|---|
| Debian package | Debian, Ubuntu and derivatives, x86-64 | hmailserver_X.Y.Z_amd64.deb |
| Debian package | the same, AArch64 | hmailserver_X.Y.Z_arm64.deb |
| RPM | Fedora, RHEL, openSUSE and derivatives, x86-64 | hmailserver-X.Y.Z-1.x86_64.rpm |
| RPM | the same, AArch64 | hmailserver-X.Y.Z-1.aarch64.rpm |
Each has a Sigstore .cosign.bundle beside it, signed by the same workflow that
signs the installer; verify one the same way (Installing hMailServer has the
cosign verify-blob line). The names are not cosmetic: a Linux server's update
checker builds the name its own package manager and architecture would install
and looks for exactly that on the release page.
Two more things exist and are not release assets. A PKGBUILD for Arch is in
the tree (hmailserver/source/Server/platform/packaging/PKGBUILD); it builds
from the tag on your own machine, which is what Arch asks for. And
build-appimage.sh wraps a built tree as an AppImage - a try-it-out artefact
for a daemon that is not meant to run out of a home directory, and labelled as
such on its way out.
sudo apt install ./hmailserver_6.3.0_amd64.deb # Debian, Ubuntu
sudo dnf install ./hmailserver-6.3.0-1.x86_64.rpm # Fedora, RHELThe packages declare their library dependencies automatically (dpkg-shlibdeps for the .deb, rpm's own auto-requires), so libpq is pulled in with them. If you are
going to use MySQL or MariaDB, install its client library yourself: the
server opens libmariadb.so.3 at run time rather than linking it, so no
package manager will do it for you - libmariadb3 on Debian and Ubuntu,
mariadb-connector-c on Fedora and RHEL, mariadb-libs on Arch.
The package installs the server enabled and stopped, on purpose. It has no database yet, and a mail server that cannot reach one writes an error to the log every second until somebody notices. The post-install message says what to do next; the next section is the long form of it.
What the maintainer scripts do, so you know what to undo:
| Create | the hmailserver system user and group |
| Create |
/var/lib/hmailserver and its temp, events and database subdirectories, and /var/log/hmailserver, all 0750 hmailserver:hmailserver
|
| Install |
/etc/hmailserver/hMailServer.ini at 0640 root:hmailserver - readable by the service, writable only by root |
| Enable |
hmailserver.service, without starting it |
| On upgrade | run hmailserver --upgrade-database as the service user (only if a database is configured), then try-restart the service if it was running |
| On remove | stop and disable; leave the mail store and the logs alone, and say so |
On purge (.deb) |
remove /etc/hmailserver as well; still leave the store |
1. Create the database and its user. PostgreSQL:
sudo -u postgres createuser --pwprompt --createdb hmailserverWith --createdb the server creates the database itself in step 4. If you
would rather the service role could not create databases - which is the
tidier policy - leave the flag off and create it yourself:
sudo -u postgres createuser --pwprompt hmailserver
sudo -u postgres createdb --owner hmailserver hmailserverStep 4 notices an existing, empty database and builds the schema inside it;
it refuses one that already holds an hMailServer schema and names
--upgrade-database instead.
2. Tell the server where it is.
sudoedit /etc/hmailserver/hMailServer.iniTwo things to change, and the file has a paragraph on each:
-
[Database] Type-PostgreSQLorMySQL. -
[Database] Server,Database,Username,PasswordandPort. Write the port out (5432,3306); it goes into the connection string as it stands and there is no useful default.
Leave AdministratorPassword alone; the next step writes it.
3. Set the administrator password. It is read from standard input with echo off, hashed with PBKDF2 exactly as the Control Panel hashes it on Windows, and written into the file. The file is root-owned, so this runs as root:
sudo hmailserver --set-admin-password4. Create the schema.
sudo -u hmailserver hmailserver --create-databaseIf the database is not there, this connects to the server the [Database]
section names with no database selected, creates it in the backend's own
dialect and reconnects; if it is there and empty, it uses it. Either way it
then runs the create script for the backend's type - what DBSetupQuick does
over COM on Windows. It refuses a database that already holds a schema, and
refuses the two Windows-only backends (SQL Server and SQL Server Compact) by
name.
5. Check what it read, before opening anything.
sudo -u hmailserver hmailserver --check-configIt prints the configuration path, the directories and the database type it
made of what you wrote, and exits without opening a listener or the database.
Database type: 0 means the Type key did not take.
6. Start it.
sudo systemctl start hmailserver
sudo systemctl status hmailserver
journalctl -u hmailserver -f7. Turn on the REST API, which is how you will administer it. In the
configuration, [Settings] RestApiPort=8045 and RestApiBindAddress=127.0.0.1
(loopback, unless you also set RestApiCertificateFile and
RestApiPrivateKeyFile), then:
sudo systemctl reload hmailserver # SIGHUP: re-reads the configuration
curl -u Administrator http://127.0.0.1:8045/api/v1/statusA reload stops and restarts the listeners inside the running process, so do it
when nothing is mid-delivery. The user name is Administrator, as on Windows.
8. Your first domain.
curl -u Administrator -H "Content-Type: application/json" \
-d '{"name":"example.com","active":true,"postmaster":"postmaster@example.com"}' \
http://127.0.0.1:8045/api/v1/domainsThe name is checked exactly as the Control Panel checks it (400 with its
sentence if it is not a valid domain name, 409 if it already exists), and
every other setting takes the default a new domain gets there. PUT /api/v1/domains/example.com with {"active":false} switches it off;
DELETE removes it with its accounts, aliases, lists and directories.
Creating and deleting a domain are server-wide: an API key restricted to
named domains gets 403.
Then create the account over REST and send yourself a message - the table at the top of this page is the sequence that was run.
hmailserver --help, verbatim in substance:
| Option | What it does |
|---|---|
--config <file> |
The configuration file to read. Default: hMailServer.ini beside the executable, then /etc/hmailserver/hMailServer.ini
|
--foreground |
Run in the foreground and log to standard error as well as to the log directory. This is the default; the option exists so the unit file can say so |
--check-config |
Read the configuration, report what it says, exit without opening a listener or the database |
--set-admin-password |
Read a new administrator password from standard input (echo off), hash it with PBKDF2, write it to the configuration, exit |
--create-database |
Create the database [Database] names on the server it names, and run the create script for its type |
--upgrade-database |
Run every upgrade script from the database's version to this build's, in order. Refuses a database from a newer build; stops rather than loops if a script runs and the version does not move |
--version, --help
|
Signals: SIGTERM and SIGINT stop the server; SIGHUP re-reads the
configuration (what the Control Panel's Reinitialize does); SIGPIPE is
ignored, so a peer that hangs up cannot kill the process.
From the package's install rules:
/usr/bin/hmailserver the server; one file
/usr/bin/tlds.txt, /usr/bin/dh2048.pem read from beside the binary; the second is
required by every TLS context
/usr/share/hmailserver/DBScripts/*.sql schema creation and upgrade scripts
/usr/lib/systemd/system/hmailserver.service the unit
/etc/hmailserver/hMailServer.ini the configuration (a conffile: an upgrade
never overwrites it)
/etc/logrotate.d/hmailserver the log rotation rule
Created by the maintainer scripts, and therefore not removed with the package:
/var/lib/hmailserver the mail store: one directory per domain, one per mailbox
/var/lib/hmailserver/temp scratch space for message assembly and backups
/var/lib/hmailserver/events event scripts
/var/log/hmailserver the logs
The six [Directories] keys in the packaged configuration point at exactly this
layout, and since 6.3.0 a relative value in any of the five non-program
directories is resolved against ProgramFolder, so a moved installation can be
written as one absolute path rather than six (Relocating an Installation).
There is no Control Panel and no COM here. Three surfaces:
-
The configuration file. Everything in the Settings Reference that is
an
hMailServer.inikey applies unchanged; the packaged file has a paragraph on every key it sets.WindowsEventLogEnabled=1is a Windows inheritance in name only - on Linux it means syslog, and the operational events (database down, a listener that could not bind, a failed backup, the disk floor) reach the journal through it. -
Directory authentication is LDAP, and only LDAP:
[LDAP] Enabled=1withServer,Security(2 = LDAPS, 1 = StartTLS) and a simple bind, proven against OpenLDAP. There is noLogonUserhere, so a directory-linked account with LDAP switched off is refused with HM6421 naming the settings to set. -
Stored secrets - the database password in the configuration, route and
fetch-account passwords, the TOTP secret - are protected under a key the
server makes on first use,
<DataFolder>/.hmailserver-secret-key(32 bytes, mode 0600), with AES-256-GCM; the stored form startsLINUX1:. The key file travels with the data directory: back it up with the database, and a secret moved to a machine without it cannot be opened (HM6414). A WindowsDPAPI:secret is likewise unreadable on Linux and is reported once. -
The REST API (The REST API). Accounts, aliases, settings, the queue,
the message store, the self-service portal. Authenticate as
Administratorwith the password from step 3. - The Control Deck, served by the same listener (Control Panel Pages): the settings, logs, certificates and rules pages read today; the writes are the roadmap row named above.
The server's own logs are in /var/log/hmailserver, in the same format as on
Windows (Troubleshooting reads them), and the files the server marks with a
byte-order mark - the backup and event logs, Sieve scripts, the backup index -
are UTF-16LE on both platforms, so a file written on one reads on the other.
A memory-safety fault is recorded in /var/log/hmailserver/crash-oracle.log
(one line: signal, address, thread, event number), after which the process dies
by the signal it caught and the kernel's core-dump policy applies; the unit
file says how to allow a core, and why it is off by default. The journal carries the startup line,
anything written to standard error, and the operational events. The logrotate
rule uses copytruncate because the server does not reopen its log on a
signal; the rule says so at length.
journalctl -u hmailserver -f
tail -f /var/log/hmailserver/hmailserver_$(date +%F).logInstall the new package. On an upgrade the maintainer scripts run
hmailserver --upgrade-database as the service user (only when a database is
configured) and then try-restart the service if it was running. A failure of
the schema upgrade is reported and does not fail the package - the binary is
already in place, and the server's own log is the better place to read why - so
read what the upgrade printed:
sudo -u hmailserver hmailserver --upgrade-database # safe to run by hand; "nothing to do" when doneThe configuration is a conffile and is never overwritten. The server's update checker, when enabled, looks for the package name its own platform would install and tells you; the apply step refuses on Linux, saying that the helper it needs is a Windows program, because an unattended package install is not something a mail server should do to itself.
In the tree since 11 September 2026; the first image is published with 6.3.2.
The same package as a container image, ghcr.io/progressiverobot/hmailserver,
with the database, the REST listener and the administrator password written from
the environment on start: Running in a Container. Everything on this page
about what the server is, how it is administered and where things are applies
to the container too; that page says what differs, which is mostly how the API
is reached.
In the tree since 11 September 2026; ships with 6.3.2.
An auto-ban (repeated failed logons from one address) is enforced by the server's own listeners: the kernel accepts the connection, the server refuses it. Two ways to push the ban below the server, and one is enough:
fail2ban, which needs no capability at all because it runs as root and reads
the application log. The package installs /etc/fail2ban/filter.d/hmailserver.conf
and a jail at /etc/fail2ban/jail.d/hmailserver.conf, disabled as Debian asks of
a shipped jail. The filter matches the two fixed-shape lines the server writes for
every counted failure and every ban, whether or not protocol logging is on
(AutoBanLogonEnabled, on as shipped, is what writes them). Turn it on:
printf '[hmailserver]\nenabled = true\n' > /etc/fail2ban/jail.d/hmailserver.local
systemctl reload fail2ban
fail2ban-client status hmailserver
The server itself, with AutoBanFirewall=1 under [Settings]: on every ban
and every expiry it runs /usr/lib/hmailserver/autoban-hook, which keeps an
nftables set with a timeout (iptables where there is no nft) and drops TCP from
the banned address to the ports the server listens on. Changing the firewall
needs CAP_NET_ADMIN, which the unit deliberately does not grant a mail server
by default. Grant it once, with a drop-in, and the hook's check verb says
whether it can act:
systemctl edit hmailserver
[Service]
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
systemctl restart hmailserver
sudo -u hmailserver /usr/lib/hmailserver/autoban-hook check
AutoBanCommand runs any program of yours instead of, or as well as, the hook -
<command> ban <address> <minutes> <ports> and <command> unban <address> - for a
cloud firewall or a router. And before turning either on, list the addresses you
administer from in AutoBanNeverBan: a ban that reaches the firewall locks that
address out of every mail port on the machine, not just out of one connection.
Stated here rather than discovered later. Each is a row in the roadmap's Linux section, which is where the current state lives.
| Gap | What it means for you |
|---|---|
| The regression suite, in part |
hmailserver/test/LinuxRegressionTests compiles 260 of the suite's files in place - not copies of them, the same text the Windows gate runs - and puts 1,405 of the suite's 2,175 tests against a Linux server. Measured for 6.3.0: 756 pass, 649 skip, 0 fail, in about 40 minutes, and CI runs them on every push with no continue-on-error, so one failing test is a red job. A little of what skips genuinely cannot be asked over HTTP - the COM-only Sieve evaluation, the suite's fake DNS zone, public folders - but most of it is simply routes nobody has written yet: 299 skip sites across 83 reasons, the heaviest being the message object, distribution lists, fetch accounts and folder ACLs. A green job that skips nearly half of what it was handed is worth having; it is not yet the same thing as a suite that tests the Linux server |
| AArch64 on hardware | CI builds and installs the packages on an ARM runner; nobody has installed one on ARM hardware by hand yet |
| Directory authentication is a simple bind over LDAPS or StartTLS, and only that |
[LDAP] BindMethod=1 (Negotiate) is Windows SSPI; on Linux it is refused (HM6420) as a directory failure, not a wrong password. The directory's certificate must chain to the system trust store, and Server must match the name in that certificate |
| No re-keying command | The stored-secret key file is made once and never rotated; replacing it means re-entering every stored password |
The packaging README has the full text; the short form:
sudo apt install cmake ninja-build clang libssl-dev zlib1g-dev libpq-dev \
libboost-thread-dev libboost-chrono-dev libboost-filesystem-dev libboost-regex-dev rpm file
export CC=clang CXX=clang++
cmake -S hmailserver/source/Server -B build/linux -G Ninja \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build/linux
cmake --build build/linux --target package # the .deb and the .rpmclang is a preference, not a requirement: GCC 13 and later builds the same
tree (export CC=gcc CXX=g++), and CI builds with both.
build/linux-tu-census.sh compiles every core source on its own and prints how
many a POSIX compiler accepts; --target aarch64-linux-gnu is the cross
measurement. CI runs both on every push and fails when a single translation unit
stops compiling.
hMailServer 6.3.2 · AGPL-3.0-or-later · Repository · Report a documentation error
Hmail Server — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- The Control Panel
- Your First Domain and Mailbox
- Connecting a Mail Client
- DNS for Your Domain
2. Secure it
3. Operate it
- Monitoring and Health
- Backup and Restore
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Routes and Relays
- The COM API and Scripting
- The REST API
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey