---
title: "Unattended installs, winget and Chocolatey, and configuration from the environment"
url: https://www.hmailserver.co.uk/topic/28231/unattended-installs-winget-and-chocolatey-and-configuration-from-the-environment
author: "Progressiverobot"
published: 2026-09-27T19:13:13.731Z
updated: 2026-09-27T19:13:13.731Z
category: "Installation, migration & upgrades"
tags: ["installer","installation","packaging","windows","linux"]
site: hMailServer Community Forum
---

# Unattended installs, winget and Chocolatey, and configuration from the environment

*Written for 6.3.4. hMailServer 6.3.6 (6 October 2026) publishes the first container image, `registry.gitlab.com/hmailserver/hmailserver:6.3.6`; its installer exits 10 or 11 when a step after its files did not complete (it exited 0), and it makes the data, log, temp, database and event folders private to the administrators and the service. See [the 6.3.6 announcement](/topic/28276). hMailServer 6.3.7 (17 October 2026), a security release, publishes `registry.gitlab.com/hmailserver/hmailserver:6.3.7` (also tagged `6.3` and `latest`); its Windows installers carry the .NET Desktop Runtime 10.0.13, installed only where no .NET 10 Desktop Runtime is installed at all, so an upgraded server keeps the one it had; at every installation and upgrade `/ProtectFolders` hardens the program folder, `Bin` and `ControlPanel`, since an installation in a folder that took its permissions from the root of a drive let any account that could sign in to the computer replace the programs (CVE-2026-107571): before upgrading one, follow `ServiceAccount.md`'s steps, and where other accounts could sign in while it was so installed, reinstall into a new folder only the administrators may change, given to setup with `/DIR=`, since over an installation setup installs into the folder it finds; and setup waits `ShutdownDrainSeconds` plus 90 seconds for the service's stop, where it waited plus 30. Chocolatey and the apt and dnf repositories still publish nothing: no channel is live as 6.3.7 is made, and 6.3.7 is not on the Snap Store. See [the 6.3.7 announcement](/topic/28277). hMailServer 6.3.8 (2 November 2026), a security release, publishes `registry.gitlab.com/hmailserver/hmailserver:6.3.8`, now the image tagged `6.3` and `latest`, which reaches a MariaDB database, where the images of 6.3.7 and earlier carried PostgreSQL's client alone, and whose entrypoint takes the database and administrator passwords out of the environment before it runs any program; and its Helm chart starts a server, where the charts of 6.3.6 and 6.3.7 never started a pod. Its Windows setup ends with exit code 7 where another account than SYSTEM, the Administrators and TrustedInstaller controls the program folder, `Bin` or `ControlPanel`, or a folder or a link on the way to them, naming the `icacls` that deals with it; with exit code 12, and the service set not to start until setup runs again, where something is not as setup left it after the files; and with exit code 1 for an installation of the original hMailServer's 5.7, the reason in its `/LOG` and in `hMailServer-setup-refused.txt` in `%TEMP%`. Chocolatey's install now passes the installer `/LOG`, and that log records setup's command line, so give the administrator password in `HM_ADMIN_PASSWORD`, set in the elevated prompt, rather than with `/adminpassword` in `--install-arguments`. Once 6.3.8 is published, jobs started by hand send it to the Ubuntu PPA (`add-apt-repository ppa:hmailserver/hmailserver`), Fedora Copr (`dnf copr enable progressiverobot/hmailserver`), Docker Hub, Chocolatey (`hmailserver-progressiverobot`, listed once its moderators approve it), PyPI and the PowerShell Gallery; the signed apt and dnf repositories this topic describes are still not published ([Channels.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.8/hmailserver/docs/Channels.md)). See [the 6.3.8 announcement](/topic/28278).*

This topic covers installing hMailServer 6.3.4 without a wizard: the Windows installer's silent switches and what a silent install does with the administrator password; where the `winget` and Chocolatey packages stand; the signed apt and dnf repositories and why they are not live; and, since 6.3.4, every setting from the environment and the four setting profiles, the two ways a deployment shapes a server before it starts. The one thing to know first: **an unattended install leaves the administrator password unset unless you pass it**, and 6.3.4 is installed by hand from the release page, because neither package manager carries it and no [live update](/topic/28234) installs it ([the 6.3.4 announcement](/topic/28218)).

### The Windows installer's switches

The installer is Inno Setup, so it takes the standard switches and a few of its own.

| Switch | Effect |
|---|---|
| `/SILENT` | No wizard; progress window only |
| `/VERYSILENT` | No wizard and no progress window |
| `/SUPPRESSMSGBOXES` | Suppress message boxes; some failure paths still raise one without it |
| `/LOG="<path>"` | Write an install log; it is the only record of what happened |
| `/DIR="<path>"` | Installation directory |
| `/COMPONENTS="server,admintools,controlpanel"` | `server` is the service; `admintools` registers the COM type library; `controlpanel` installs the Control Panel, which does not need `admintools` |
| `/adminpassword=<password>` | Custom: sets the administrator password (at least 5 characters) and hands it to the database tools |
| `/upgradetoken=<hex>` | Custom: the single-use token of a live update; not for people to type |
| `/useinternaldbms=true\|false` | Custom: `true` (the default) uses the bundled SQL Server Compact database |
| `/serviceaccount=virtual\|localsystem\|keep` | Custom: `virtual` is `NT SERVICE\hMailServer`, the default for a new installation; `keep` is the default for an upgrade |
| `/profile=NAME` | Custom, since 6.3.4: the setting profile a new installation applies, or `none`. Written and read, and not run (below) |

```bat
hMailServer-x.y.z-x64.exe /VERYSILENT /SUPPRESSMSGBOXES /LOG="C:\Temp\hmail-install.log" ^
   /COMPONENTS="server,controlpanel" /useinternaldbms=true
```

**Treat a non-zero exit code as a failed install and read the log.** The installer checks both that the database tool launched and its exit code, so a failed or cancelled schema step fails the install rather than passing silently. The log has the tool's code: from `DBSetupQuick.exe`, 0 is a database created or already up to date, 1 a failed create or a `DBUpdater.exe` that would not start, 3 a wrong or missing administrator password, and any other `DBUpdater.exe`'s own code. A `hm_dbversion` still on the old value afterwards is the same failure. A silent installation does not approve folders or key files the configuration names outside the program folder, and leaves such a service on LocalSystem rather than moving it to the virtual account.

### The administrator password, silently

- **A fresh silent install leaves the administrator password unset** unless you pass `/adminpassword=<password>` or set `HM_ADMIN_PASSWORD`: without either, the `AdministratorPassword` key is left out of `hMailServer.ini` entirely.
- **Set it afterwards with `hMailServer.exe --set-admin-password`**, new in 6.3.4, from an elevated prompt, then restart the service. It takes the password from `HM_ADMIN_PASSWORD` or, when that is not set, from one line of standard input when that is a pipe or a file, and never from an argument. Prefer the variable: a pipe from Windows PowerShell 5.1 turns every non-ASCII character into `?`, storing a password nobody typed. On Linux the command is `hmailserver --set-admin-password`. [ServiceAccount.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/ServiceAccount.md) and [Upgrading.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Upgrading.md) write the Windows step as `hMailServer.exe /SetAdministratorPassword`.
- **The Control Panel and COM are refused under the virtual account.** A new 6.3.4 installation runs the service as `NT SERVICE\hMailServer` by default, and under that account `hMailServer.ini` is read-only to the service: the Control Panel's *Administrator password* card and COM's `Settings.SetAdministratorPassword` are each refused with a sentence. They set the password only where the service may write the file, as it may under LocalSystem, which an upgrade keeps unless it is answered otherwise.
- **A silent upgrade of an installation that has a password still needs it** for the database upgrade, and cannot prompt. Without it the database upgrade fails and the installer reports a non-zero exit code rather than waiting. With the password empty, a silent upgrade works.
- **Since 6.3.4, `HM_ADMIN_PASSWORD` is the safer of the two.** Inno Setup drops every double quote from its command line, so `/adminpassword=ab"cd` sets `abcd`, and anybody listing processes while setup runs can read the switch. The variable takes any character. Setup reads it only when neither `/adminpassword=` nor `/upgradetoken=` is given.
- **Set the variable in an elevated prompt.** Setup started without administrator rights elevates itself through the UAC prompt, and the variable does not cross it.

Until 6.3.4 the password went unquoted on the database tools' command lines, so one with a space, a double quote or backslashes before one failed the database step with exit code 3. It now goes in `HM_ADMIN_PASSWORD`.

### winget and Chocolatey: not in the public repositories yet

The manifests exist and are validated for each release, from the release's own Authenticode-signed installer. **They are not in the public repositories**: neither `winget install ProgressiveRobot.hMailServer` nor `choco install hmailserver` installs this fork until a first submission has been reviewed and merged.

**Do not run `choco install hmailserver` expecting this fork.** [PackageManagers.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/PackageManagers.md) records none on 15 September 2026, but on 27 September 2026 the community feed held an unlisted `hmailserver` package: the original project's 5.6.8, not this fork's.

What the packages are built to do, once accepted:

- Both run the signed installer the release page offers with `/VERYSILENT /SUPPRESSMSGBOXES /NORESTART`. `/SUPPRESSMSGBOXES` is not optional: without it a database-setup failure shows a message box, silent mode answers it with the default button, and a broken install reports success.
- `/TYPE=full` is deliberately not passed, so an upgrade keeps the components already installed and does not put the Control Panel back on a server where it was left out.
- `MinimumOSVersion: 10.0.14393.0` is Windows 10 1607, the floor of the .NET 10 Desktop Runtime the Control Panel needs.
- **The administrator password is left unset**, and neither package invents one. Set one before the server is reachable from anywhere but the machine itself.
- Uninstalling runs the installer's own uninstaller, which does not delete the message store, the database or `hMailServer.ini`.
- A pre-release is never submitted.

### apt and dnf on Linux: written, tested in a lab, not live

The project keeps signed apt and dnf repositories on the update feed's site, `https://updates.progressiverobot.com`. **They are not live.** The job that makes them, `package-repos`, was tested on the lab machine on 26 September 2026 with a throwaway key and dummy packages, and publishes nothing until the owner has made the signing key.

This is what a Debian or Ubuntu user will type once it is live; on a release with no suite, `apt update` answers 404 for its `InRelease`.

```sh
sudo install -d -m 0755 /etc/apt/keyrings
sudo curl -fsSLo /etc/apt/keyrings/hmailserver.asc https://updates.progressiverobot.com/hmailserver-repository-key.asc
gpg --show-keys /etc/apt/keyrings/hmailserver.asc   # compare the fingerprint with the one below
echo "deb [signed-by=/etc/apt/keyrings/hmailserver.asc] https://updates.progressiverobot.com/apt $(. /etc/os-release && echo "$ID$VERSION_ID") main" \
  | sudo tee /etc/apt/sources.list.d/hmailserver.list
sudo apt update
sudo apt install hmailserver
```

The fingerprint does not exist yet: [PackageManagers.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/PackageManagers.md) records it as `(not made yet)`.

**There is no dnf repository at all** until a stable release carries `.rpm` files built for each distribution, and 6.3.4 carries the generic one alone. Once one does, on Fedora and Enterprise Linux it is `sudo curl -fsSLo /etc/yum.repos.d/hmailserver.repo https://updates.progressiverobot.com/rpm/fc44/hmailserver.repo` and then `sudo dnf install hmailserver`, with `fc44` replaced by the release's directory.

**What 6.3.4 carries limits what the repositories could hold.** Its Linux packages are one generic x86-64 `.deb` and one generic `.rpm`, neither built for one distribution; [hMailServer on Linux: what you get and what you do not](/topic/28189) says where each installs. In the repositories as [PackageManagers.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/PackageManagers.md) describes them, the `.deb` belongs in the `ubuntu26.04` suite, and the `.rpm`, built on Ubuntu 26.04, goes in no repository. On 26 September 2026 `dnf install` of the `.rpm` built from `master` that day resolved its dependencies on Fedora 43 and 44 and AlmaLinux 10, and was refused on AlmaLinux 9, whose glibc and libstdc++ are older than it asks for. Packages built for each distribution come from the release after 6.3.4. The packages carry no RPM signature of their own: the signed repository metadata carries every package's SHA-256. Not tried: the job on GitLab's runners, HTTPS end to end, arm64 and aarch64. Until it is live, [First install on Linux](/topic/28190) is the walk.

### Every setting from the environment

*Since 6.3.4.* Every `[Settings]` key and every `hm_settings` row the server reads has a name in the environment.

| Variable | Sets |
|---|---|
| `HM_SETTING_<key>` | The `[Settings]` key, one of 241: `HM_SETTING_MaxSubmissionsPerIPPerMinute=30` |
| `HM_PROPERTY_<name>` | The `hm_settings` row: `HM_PROPERTY_maxmessagesize=20480` |
| `HM_SETTING_<key>_FILE`, `HM_PROPERTY_<name>_FILE` | The same, read from the file the variable names, such as a Kubernetes or Compose Secret; UTF-8, at most 64 KB, trailing line breaks stripped |

The prefixes and `_FILE` are written in capitals; the name after the prefix is matched without regard to case, and a key is stored in its own spelling.

**What is refused, before anything is stored**: a name that is not a setting of the store its prefix names (`MaxMessageSize` after `HM_SETTING_` is refused naming `HM_PROPERTY_maxmessagesize`); a misspelt prefix such as `HM_SETTINGS_`; a read-only property such as `WebPushVapidPublicKey`; the plain and the `_FILE` form of one setting together; a `_FILE` naming a directory, a missing path or a file over 64 KB, refused naming the path, never the content; the `_FILE` form of a setting a domain or an account may hold its own value of; and a value the setting's own REST check would refuse, in that check's words. `maxmessagesize=off` is refused rather than stored as 0, which is "no limit".

**The verb.**

```sh
hmailserver --config /etc/hmailserver/hMailServer.ini --apply-environment
```

`hMailServer.exe --apply-environment` on Windows is the same verb from the same code. It opens the configuration and the database as the service does, so run it as the user the service runs as. It **checks every value first and exits 1 having changed nothing** when any is refused, then writes each through the setter `PUT /api/v1/settings/...` uses and prints a line per variable: `set`, `unchanged` or `refused`. A secret's value is never printed. Exit 2 is a configuration file that names no database. The verb's writes are not rows in the audit trail: its own output, in a container the container's log, says what it changed.

**Who runs it.** No container image of 6.3.4 is published: the image is one you build yourself, from the Dockerfile in the tree. Its entrypoint runs the verb after `--create-database` and `--upgrade-database` and before the server. **On Windows nothing runs it for you**: a Windows service has no environment of its own that anything sets, so the verb is there for a script or a deployment tool. Run beside a running server, its values reach that server at the next [reinitialise](/topic/28222) (**Apply now**), or the next start for a key marked `restart`.

**The environment wins, every start.** The server records the managed names in the `hm_settings` row `EnvironmentManagedSettings` and refuses an administrator's change to one of them.

| Where | What happens |
|---|---|
| REST | A `PUT` that would change a managed key is `409`, with a sentence naming the variable; `GET /api/v1/settings/environment` lists every managed setting with no value |
| COM (Windows) | Every setter refuses with the same sentence |
| Control Deck | **Set by the environment** beside the key, with its value and no control |
| Control Panel (Windows) | The same mark, with the field disabled |
| `hmctl` | `hmctl config changed` prints `(set by the environment)`; `hmctl config export` leaves managed settings out |

Unset the variable and restart to manage the setting in the server again. A value a `_FILE` supplied stays withheld after the variable is gone: REST answers `(set)`, the Control Panel leaves the field empty, and it is never on a command line or in a log. The environment sets the **server** level only, and the two `[SendingLimits]` keys have no environment name.

**The container's own variables are not settings**: the database's `HM_DB_*`, TLS included; `HM_ADMIN_PASSWORD` and `HM_ADMIN_PASSWORD_FILE`; `HM_INI`; `HM_CREATE_DATABASE` and `HM_UPGRADE_DATABASE`; `HM_PROFILE` and `HM_PROFILE_CONFIRM`. The four REST ones are aliases: `HM_REST_PORT` stands for `HM_SETTING_RestApiPort`. The Helm chart takes `settings`, `properties` and `settingsFrom`. [In a container or on Kubernetes](/topic/28246) has the table, the chart, and the stored-secrets key a first start makes, to export at once.

**What has not been run.** The verb has been run as `hMailServer.exe --apply-environment` on Windows only. Its POSIX half compiles; the image's entrypoint as a whole, the POSIX verb against a database, the chart and the Compose file have not been executed. There is no live reload from a ConfigMap change: a restart applies it.

### Profiles: the shape a new server starts in

*Since 6.3.4.* A profile is the thirty or so settings that make a server the kind it is, each with a reason written from what the setting's reader does. Four ship as reviewed documents; there is no route that makes one of your own.

| Profile | For | What you would notice |
|---|---|---|
| `office` | One server that receives an office's mail and holds its mailboxes | SPF, the MX check, DKIM and DMARC scoring; greylisting; the quarantine; auto-ban and lockout; a password policy and the breach check (31 entries) |
| `gateway` | Behind a filtering gateway that has already judged the mail | Greylisting off; XCLIENT and an ARC seal trusted only from the gateway and sealer you name (17 entries) |
| `relay` | An outbound relay that holds no mailbox anybody reads | IMAP and POP3 closed at the next restart; hard bounces suppressed; the trace kept three months (24 entries) |
| `sender` | A high-volume sender judged on its bounce and complaint rates | The relay's shape, more deliveries at once, the feedback loops, the trace kept six months (32 entries) |

Every surface shows **a diff first**, then saves what it replaces, then writes, all or nothing. An entry that closes a listener, trusts an address range, turns a filter off or weakens a check, or shortens a window of days asks for a confirmation. **A profile never touches** a port, a path, a bind address, the database connection, a password or any secret, an IP range, Incoming relays, a DNS block list, a listener's TLS or a domain's own settings. What only you know, such as the gateway's addresses, is a **step** listed under the diff. **Revert** puts back each value the profile replaced and leaves alone one an administrator changed since. It puts back settings, not data: where a profile shortened a window of days, what the sweep deleted under the shorter window stays deleted, and a listener a profile closed opens again only at the next restart. There is one snapshot: a second apply waits for the first to be reverted or discarded.

Where a profile is chosen at install time:

- **The Windows installer** offers the four on a page of their own, after the administrator password and before the service-account page, for a new installation only, with "None" chosen until another is. No diff is shown there: each profile's sentence names the listener, filter or trust it changes, and choosing it is the confirmation, so `relay` and `sender` close IMAP and POP3 with no further question. After the database step it runs `hMailServer.exe --apply-profile NAME --once --if-new --confirm` before it starts the service. Silently, that is `/profile=NAME`. Every failure is said, and the installation still succeeds with the shipped settings.
- **The container** applies `HM_PROFILE` once, before the server starts; `HM_PROFILE_CONFIRM=yes` confirms an entry that asks, and `HM_PROFILE=none` records that no profile is wanted.
- **The verb itself**:

```text
hmailserver --apply-profile NAME [--confirm] [--once] [--if-new]
hmailserver --revert-profile
```

| Exit | Meaning |
|---|---|
| 0 | Done, or nothing to do |
| 1 | Refused or failed |
| 2 | No such profile, or no database |
| 3 | An entry needs `--confirm` |
| 4 | The service is running |
| 5 | `--if-new`, and the server is in service |

**On Windows the verbs refuse while the service runs (exit 4).** On Linux nothing says whether a server is running, so run them with the server stopped, as the container's entrypoint does. `--if-new` does nothing on a server of ten accounts or more. A setting the environment manages is skipped, with its variable named.

Afterwards a profile is chosen in the Control Panel's **Maintenance, Setting profiles** (Windows), the Deck's **Checklist**, COM's `Settings.ApplyProfile` (Windows), REST or `hmctl`. Read the diff at `GET /api/v1/settings/profiles/{name}`, or with `hmctl settings profile NAME`, which prints a `diff_token`. Apply with `{"confirm": true, "diff_token": ...}` on `POST /api/v1/settings/profiles/{name}/apply`, or `hmctl settings apply-profile NAME` with `--confirm TOKEN`: a diff that has moved since it was read is refused (`409`) and nothing is written. The way back is `POST /api/v1/settings/profiles/revert`; `POST /api/v1/settings/profiles/discard` drops the snapshot.

**The installer page with its `/profile=NAME` switch, the container's `HM_PROFILE` and the Linux verbs have been written and read, and not run**: the installer was not built and the Linux server not compiled for this change, and no container was started.

### What it does not do

- No package configures the server: no password, no domain, no firewall port.
- No export of the configuration as an environment.
- Four profiles, no parameters, no profile per domain.

### Where to read more

- The wiki pages: [Profiles and Environment](https://gitlab.com/hmailserver/hmailserver/-/wikis/Profiles-and-Environment) and [Running in a Container](https://gitlab.com/hmailserver/hmailserver/-/wikis/Running-in-a-Container)
- winget, Chocolatey, apt and dnf: [PackageManagers.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/PackageManagers.md)
- The naming rule and every refusal: [EnvironmentConfiguration.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/EnvironmentConfiguration.md)
- Every entry of the four profiles: [Profiles.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Profiles.md)
- The silent upgrade: [Upgrading.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/Upgrading.md)
- The documentation page: [Run the installer](https://www.progressiverobot.com/hmailserver-documentation/#42-run-the-installer)
- On this forum: [Upgrading to 6.3.4](/topic/28193), [Installing on Windows](/topic/28227) for the wizard's pages, and [Behind a gateway](/topic/28240) for the gateway profile's steps.
