The hmailserver command line on Linux: every verb, who runs it, the files, the unit
-
Written for 6.3.4. hMailServer 6.3.6 (6 October 2026) carries .deb and .rpm packages for x86-64 and AArch64, one for each of Debian 12 and 13, Ubuntu 24.04, Fedora 43 and 44, Enterprise Linux 9 and 10, and openSUSE Leap 16.0 and Tumbleweed, both AppImages and the first container image. Its commands say what they did on their own output rather than in the error log, and the store commands run as root refuse a data directory that another account could have linked into. See the 6.3.6 announcement. From 6.3.6 the root helper applies hMailServer 6.3.7 (17 October 2026), a security release, by the live update, for the generic
.deband.rpmof either architecture and both AppImages; a server from one of 6.3.6's per-distribution packages is offered the generic package, whichaptrefuses on Debian 12 anddnfon Enterprise Linux 9, and is upgraded with its package manager and its release's own package, and from 6.3.4 or 6.3.5 install 6.3.7 withapt,dnforzypper, not by the live update. A server whoseUpdateSigningIdentity,UpdateSigningIssuerandUpdateSourceRepositorystill name the path the project began at refuses 6.3.7 and 6.3.8 untilsudo hmailserver --set-setting <name>=clears each of the three and the service is restarted. See the 6.3.7 announcement. From 6.3.6 or 6.3.7 the root helper applies hMailServer 6.3.8 (2 November 2026), a security release, by the live update in the same way; a server from one of 6.3.6's or 6.3.7's per-distribution packages is upgraded with its package manager and its release's own package, and from 6.3.4 or 6.3.5 install 6.3.8 withapt,dnforzypperrather than by the live update, or turn the live update's apply off first withsystemctl disable --now hmailserver-update.path. 6.3.8 names files in UTF-8 whateverLANGsays: on a server that ran under aLANGthat is not UTF-8, rename each file and folder named outside ASCII to its UTF-8 name before upgrading, for example withconvmv -f iso-8859-1 -t utf-8 -r --notest <folder>. The values--set-setting,--apply-profile,--accountand--domaintake, and--config, are read as UTF-8 and refused with exit 2 when they are not. See the 6.3.8 announcement.On Linux the server is one executable,
/usr/bin/hmailserver, and what cannot be done over the REST API, from creating the schema to rewriting the message store, is done with its own options. This topic lists every verb 6.3.4's documents name and who runs it, where the package puts its files, what the systemd unit lets the service touch, and how the root helper applies a live update. What a Linux server has and lacks is in hMailServer on Linux, the first install in First install on Linux. The one thing to know first: on a package installation/etc/hmailserver/hMailServer.iniis0640 root:hmailserver, and the service cannot write it.Where the package puts things
Path What it is /usr/bin/hmailserverthe server, one file /usr/bin/tlds.txt,/usr/bin/dh2048.pemread from beside the binary; the second is required by every TLS context /usr/share/hmailserver/DBScripts/*.sqlthe schema creation and upgrade scripts /usr/lib/systemd/system/hmailserver.servicethe unit /etc/hmailserver/hMailServer.inithe configuration, a conffile an upgrade never overwrites; since 6.3.4 its [Settings]section is a copy of the database/usr/bin/hmctlsince 6.3.4, the command-line client over the REST API /etc/logrotate.d/hmailserverthe log rotation rule /etc/fail2ban/filter.d/hmailserver.conf,/etc/fail2ban/jail.d/hmailserver.confthe fail2ban filter and jail, the jail disabled as shipped /usr/lib/hmailserver/hmailserver-update,/usr/lib/hmailserver/autoban-hookthe root update helper (since 6.3.4) and the firewall hook /var/lib/hmailserver, withtemp,eventsanddatabaseunder itthe mail store, one directory per domain and one per mailbox; scratch space; event scripts /var/log/hmailserverthe logs What the maintainer scripts do. They create the
hmailserversystem user and group, and the last two rows above, all0750 hmailserver:hmailserver; install the configuration; and enablehmailserver.servicewithout starting it, on purpose, because there is no database yet. On an upgrade they runhmailserver --upgrade-databaseas the service user, only if a database is configured, thentry-restartthe service if it was running. On removal they stop and disable, and leave the mail store and the logs alone; a.debpurge removes the configuration as well, and/etc/hmailserverwith it when nothing else is in it, and still leaves the store.Which packages exist. 6.3.4 carries two x86-64 packages,
hmailserver_6.3.4_amd64.debandhmailserver-6.3.4-1.x86_64.rpm, and no container image of 6.3.4 is published. The.debinstalls on Ubuntu 26.04 and 24.04, not on Debian 12; the.rpmon Fedora 43 and 44 and Enterprise Linux 10, not on Enterprise Linux 9; the rest of the platform picture is in hMailServer on Linux. The packages carry no Sigstore bundle, so no live update installs them: 6.3.4 is installed by hand (Upgrading to 6.3.4).Who runs what
As root (
sudo), because the file is root's:--set-admin-password,--set-setting, and the four stored-secrets verbs. All but the export write/etc/hmailserver/hMailServer.ini, and the export a new file of its own (below);--set-settingkeeps the file's owner and mode.As the service user (
sudo -u hmailserver), because the verb opens the database or writes the data directory: the rest, from--create-databaseto the store walks.--apply-new-install-defaultsrefuses to run as root (exit 2), whose certificate key the service could not read, and--sample-domainrun as root leaves today's log owned by root.Two things follow from the file being root's. The running server cannot write its copy of a stored value back into
[Settings]: a value stored over the API is in effect and the file's line goes stale, which the server says once a start in the application log, not as an error. The stale line is never taken for an edit, so nothing needs changing by hand; only what reads the file itself, such as a server that cannot read its table, sees the older value (how the settings store works). The exception is a[Settings]secret sealed once the stored-secrets key exists (below): its line cannot be rewritten, andHM5803names it at each start untilsudo hmailserver --set-setting <name>writes it. And a server that verifies an older MD5 or SHA-256 administrator password hash cannot write it again as PBKDF2: it says so once a process (HM7494), andsudo hmailserver --set-admin-passworddoes it.Every verb
Every row from
--check-databaseto the stored-secrets verbs is new since 6.3.4.Verb Runs as What it does --config <file>The configuration to read. Default: hMailServer.inibeside the executable, then/etc/hmailserver/hMailServer.ini--foregroundthe unit Run in the foreground and log to standard error as well as the log directory. It is the default --check-configservice user Print the configuration path, the directories and the database type, and exit without opening a listener or the database. Database type: 0means theTypekey did not take--set-admin-passwordroot Read a new administrator password from standard input with echo off, hash it with PBKDF2, and write it to the file --create-databaseservice user Create the database [Database]names, or use an existing empty one, and run the create script for its type. Refuses SQL Server and SQL Server Compact by name. Since 6.3.4, says the wiki's Installing on Linux, a database that holds this build's schema or an older one is left as it is with exit 0, and a newer one exits 1; 6.3.3 refused any database that held a schema. The documentation page (35.4, 35.7) still says a schema is refused, exit 1: test it on a scratch database first--upgrade-databaseservice user 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. Safe to run by hand --check-databaseservice user Connect once with TlsModeandTlsCaFile, say whether the connection is encrypted and the certificate checked: exit 0 connected, 1 not, 2 not configured. Changes nothing, and runs beside a running service--set-setting NAME=VALUE,--set-setting NAMEroot Store one [Settings]value in the database and write the server's copy into the file (below)--apply-environmentservice user Store every setting the environment names ( HM_SETTING_<key>,HM_PROPERTY_<name>, their_FILEforms, the container'sHM_REST_*), each checked first: exit 1, with nothing stored, if one is refused. It writes the file's copy too, so the file must be writable, as the container's is; where it is not, as for the service user on a package installation, the verb refuses before it stores anything. EnvironmentConfiguration.md says it has been run on Windows only, and on Linux compiled but not run: try it on a scratch database first--apply-profile NAME [--confirm] [--once] [--if-new],--revert-profileservice user, server stopped Apply one of the four setting profiles ( office,gateway,relay,sender;nonerecords that none is wanted), or put back what the last one changed. Exit 3 means an entry needs--confirm, 5 that--if-newfound ten accounts or more. On Windows the verb refuses while the service runs (exit 4); Profiles.md says that on Linux nothing tells it whether a server runs, and that the POSIX verbs have been written and read, and not run: try them on a scratch database first--apply-new-install-defaults [--if-marked [<file>]]service user, server stopped The secure defaults of a new installation (below). Exit 0 applied, 1 something could not be written ( HM7510,HM7511), 2 no database or run as root, 5 not a database this installation created, or not as the create script left it--sample-domain create,--sample-domain removeservice user Make or remove the throwaway example.test. Exit 0 done, 2 refused, 1 failed. Remove it before the server takes real mail--measure-storeservice user What compressing the store and holding its large parts once would save. Changes nothing, and runs beside a running server --compress-store [--decompress],--recount-storeservice user, server stopped Rewrite the store in place, or back to plain RFC 822; recount the parts held once. Refused while the server runs (exit 4): on Linux the server holds a lock in the log directory for as long as it runs --encrypt-store,--decrypt-storeservice user, server stopped Encrypt what a mailbox encrypted at rest stored before it was switched on, or put it back. --decrypt-storereads the domain's recovery passphrase fromHMAILSERVER_RECOVERY_PASSPHRASE, never from the command line--copy-store-to-object-storage,--copy-store-from-object-storageservice user Copy the message store into the object store the settings name, or back, each file verified and a stopped run resumed. They run beside the server; --remove-sourceremoves what was copied from once its copy is verified, and only with the server stopped (exit 4 beside it)--verify-update <file>Check a downloaded package or AppImage against the Sigstore bundle beside it; exit 0 when a signer the server trusts made it --create-stored-secrets-key,--export-stored-secrets-key <file>,--import-stored-secrets-key <file>,--forget-sealed-secrets <key id>root Make the stored-secrets key, export it, import it on another node, or, with the server stopped (exit 4 beside it), clear what was sealed under a key lost for good (below) --version,--help--measure-store,--compress-store,--encrypt-store,--decrypt-storeand the two copies take--account <address>for one mailbox or--domain <name>for one domain's, and neither for the whole store;--decrypt-storeneeds one of the two.Signals.
SIGTERMandSIGINTstop the server.SIGHUP, whichsystemctl reload hmailserversends, re-reads the configuration; it stops and restarts the listeners inside the running process, so do it when nothing is mid-delivery. Since 6.3.4 the server drains before it stops: the mail listeners close at the socket, so senders retry, andShutdownDrainSecondslets what is in flight finish. At its default of 0 nothing is waited for, and a session mid-DATA at the moment of the stop is cut: set it on a production server, where Upgrading.md calls 30 a reasonable figure.--set-setting: the way in before the API exists (since 6.3.4)From schema 6042 the database is the settings store. Every
[Settings]key the file holds at the server's first start is taken into the database then, the packagedRestApiPort=0among them. Afterwards a line edited in the file is reported in the error log asHM5804and the stored value is used, so an edit to the file brings no listener up, and with the listener off nothing that speaks the API can change it either.sudo hmailserver --set-setting RestApiPort=8045 sudo hmailserver --set-setting RestApiBindAddress=127.0.0.1 sudo systemctl restart hmailserverThe verb stores the value as the REST API does and prints what it stored. It refuses a name the server's settings loader does not read, a whole number that is not one, a port that is not 0 to 65535, and a
RestApiBindAddressthat is not an IP address orlocalhost: the checks--apply-environmentmakes, in the same words. A secret's value is refused on the command line, where the shell's history, the process list and sudo's log would keep it. Give the name alone,sudo hmailserver --set-setting SRSSecret, and type the value at a prompt that does not echo it, or pipe it in.Which sections and keys stay in the file rather than the database, and the file's
[SettingsOverride]section, which forces a value over the stored one (HM5807,HM5808), are in Settings: what is not stock, when a save takes effect.The stored-secrets key on Linux (since 6.3.4)
A Linux server has two secret stores. The machine's is the key file
<DataFolder>/.hmailserver-secret-key, mode 0600, made by the server on first use: the database password in the configuration and the route and fetch-account passwords are kept under it asLINUX1:envelopes. It travels with the data directory. A secret moved to a machine without it cannot be opened (HM6414), and there is no re-keying command: replacing the file means re-entering every stored password. The installation's is the stored-secrets key,[Security] StoredSecretsKey, under which each account's TOTP second factor and the[Settings]secrets are sealed in the database asHMK1:envelopes, so that every node sharing the database can open them.The service never makes it. On a package installation
--create-databaseruns as the service user, cannot write the root-owned file, makes no key and says what to run instead. An upgrade makes none. Until a key exists those secrets are kept as written, and the setup checklist'sstored_secrets_keyitem offers the step. Make the key, export it and restart the service; nothing is sealed until that restart:sudo hmailserver --create-stored-secrets-key sudo hmailserver --export-stored-secrets-key /root/hmailserver-stored-secrets.key sudo systemctl restart hmailserverKeep the exported file with the database backups, apart from them: a database dump restored without it brings back every second factor and
[Settings]secret unopenable. Carrying the key to a standby with--import-stored-secrets-key, what a node without it says (HM7495) and--forget-sealed-secretsfor a key lost for good are in Hardening a public mail server.The unit, and what it lets the service touch
The packaged unit runs the server with
--foregroundashmailserver, and before every start:ExecStartPre=-/usr/bin/hmailserver --apply-new-install-defaults --if-marked TimeoutStartSec=300The unit's hardening:
ProtectSystem=strict, which leaves/etcread-only to the service;/usrread-only, which with the single capability below is why the service can neither run the package manager nor stop itself;ProtectHome=yes, which hides/home;ReadWritePathsof/var/lib/hmailserverand/var/log/hmailserver;RuntimeDirectory=hmailserver, which is/run/hmailserver; and one capability,CAP_NET_BIND_SERVICE, which binds the mail ports.CAP_NET_ADMINis deliberately not granted, so the firewall hook behindAutoBanFirewallcannot act until a drop-in (systemctl edit hmailserver) adds it toAmbientCapabilitiesandCapabilityBoundingSet;sudo -u hmailserver /usr/lib/hmailserver/autoban-hook checksays whether it can. ADataFolderoutsideReadWritePathsneeds a drop-in too, before the first start:sudo systemctl edit hmailserver # [Service] # ReadWritePaths=/srv/mailA memory-safety fault is recorded in one line of
/var/log/hmailserver/crash-oracle.log; core dumps are off by default.The first start secures a new installation. On a database
--create-databasemade, theExecStartPreline gives the server a self-signed certificate, STARTTLS on 25, 587, 110 and 143, and TLS required for authentication on the Internet IP range; mail clients warn about the certificate until ACME (Let's Encrypt certificates) or your own replaces it. It acts only on a database marked within a day of its clock and still as the create script left it; an older mark is kept for a run by hand,sudo -u hmailserver hmailserver --apply-new-install-defaultswith the server stopped, and an upgraded or attached database is never changed. The mark, the certificate and the checklist item that follows up are in Hardening a public mail server.The root helper
hmailserver-update(since 6.3.4)A live update is applied outside the server's unit. The server writes a one-file request into
/run/hmailserver;hmailserver-update.path, a root path unit the package enables, takes it and runs/usr/lib/hmailserver/hmailserver-update, a shell script readable end to end. The script:- checks every line of the request against root's own configuration;
- verifies the package, and the rollback image, again as root against their Sigstore bundles, with
hmailserver --verify-update: the check the server made, made by a process the server could not have influenced; - refuses anything that is not a genuine upgrade: the package's own version is compared with what
dpkgorrpmsays is installed, so a signed but superseded release cannot be put back; - stops the unit, installs with
apt-get/dpkgordnf/rpm, starts the unit, and waits for the server to stay up, and for/readyzwhen the metrics listener is on; - reinstalls the previous version if it does not, and writes one line to
<DataFolder>/Updates/last-apply.txt, which the server reports at its next check and the Control Deck shows.
A refused request is explained in
journalctl -u hmailserver-updateand nowhere else, on purpose.sudo /usr/lib/hmailserver/hmailserver-update checknames the installer it would use, whether the path unit is active and whether the running unit has the runtime directory the request needs. The Debian and RPM packages enable and start the path unit; Arch does not enable units from a package, so there
sudo systemctl enable --now hmailserver-update.pathis yours to run. Nothing happens unless the update check is on and the install is asked for, from the Control Deck or over the API, and only for a release signed by a signer the server trusts, which 6.3.4 is not.hmctland the PowerShell moduleThe other command line is
hmctl(/usr/bin/hmctl, one Python 3 file), with theHmailServerPowerShell module beside it in the repository. Both speak the REST API, so both administer a Windows or a Linux server, here or on another machine. They cannot turn the REST listener on, set the administrator password, or make or carry the stored-secrets key. They have a topic of their own: hmctl and the PowerShell module.Logs and the journal
The server's own logs are in
/var/log/hmailserver. The journal (journalctl -u hmailserver -f) carries the startup line, standard error and the operational events:WindowsEventLogEnabled=1is a Windows inheritance in name only, and on Linux means syslog. The logrotate rule usescopytruncate, because the server does not reopen its log on a signal.Where to read more
- On the wiki: Installing on Linux, and Command Line for
hmctl. - CommandLine.md, SecretsAtRest.md, SecureDefaults.md, Profiles.md and MessageStore.md.
- The documentation page: 35.2 Supported platforms and packages, 35.7 Command-line reference, which lists none of the verbs new in 6.3.4, and 35.8 The systemd service.
- On this forum: hMailServer on Linux, First install on Linux, Upgrading to 6.3.4 and The Control Deck; Databases on Linux for
--create-databaseand the schema upgrade; the update check and the live update for what the root helper is asked to apply; and message storage for what the store verbs change.
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login