-
Notifications
You must be signed in to change notification settings - Fork 3
Relocating an Installation
Moving a configured installation to another directory or drive. The Installation paths diagnostic and the relative [Directories] values it describes are in the tree after 6.2.28, not yet released. This is the wiki copy of docs/RelocatingAnInstallation.md, which is the one the line references were checked against; the two are kept the same.
Moving a configured installation from one directory to another - C:\Program Files (x86)\hMailServer to C:\Program Files\hMailServer, or onto another
drive - is not one change. The installation path is recorded in the registry, in
the service, in the COM registration, in hMailServer.ini, and in a handful of
database columns that hold absolute file names an administrator typed. This is
the ordered list of every one of them, what repairs each, and the two places
where the honest answer is "there is no clean fix".
It is written for 6.2.28. Every claim below was read out of the code; the file and line references are there so you can check any of them.
Installing somewhere new is a different, solved problem. /DIR="<path>" on
the installer puts a fresh installation wherever you want. This document is
about an installation that already has mail in it.
The good news, first. The mail store itself is already relocatable. Message
rows hold a bare {guid}.eml with no directory (Message::GenerateFileName,
Common/BO/Message.cpp:261), and the path is rebuilt at every read against the
data directory (PersistentMessage::GetFileName,
Common/Persistence/PersistentMessage.cpp:1502). Moving the data directory and
pointing DataFolder at its new home moves every message with it. The exception
is a database that predates hMailServer 5.4, where the column can hold a full
path; step 0 tells you whether yours does.
-
Take a backup and verify it restores. Everything below is reversible only while the old tree and a good backup both exist.
-
Ask the server whether its message rows are relative. In the Control Panel, Monitoring & troubleshooting → Diagnostics → Test message file locations (Monitoring and Health §16.8) (
Common/Diagnostics/TestDataDirectory.cpp:31). If it reportsERROR: Full paths are stored in the database, the move is still possible but step 8 becomes mandatory rather than optional. -
Write down what you are about to strand. The inventory is in step 1. Doing it afterwards means finding out from a failure.
| Section | Key | What breaks if it is left pointing at the old tree |
|---|---|---|
[Directories] |
ProgramFolder |
Language files, the database scripts and 7-Zip for backups are looked for under it (IniFileSettings.cpp:154, :1072, Compression.cpp:84) |
[Directories] |
DataFolder |
Every message path is rebuilt from it. The store appears empty |
[Directories] |
DatabaseFolder |
The SQL Server Compact database file, if you use that backend |
[Directories] |
LogFolder |
Logs are written to the old tree, silently |
[Directories] |
TempFolder |
Message assembly and backup staging |
[Directories] |
EventFolder |
Event scripts are not found; events stop running |
[Settings] |
ArchiveDir |
Archiving stops; existing archived copies are not found |
[Settings] |
AcmeCertificateDirectory |
ACME state and issued certificates |
[Settings] |
OAuth2PublicKeyFile, UpdateTrustRootsFile, UpdateLogPublicKeyFile
|
Token validation and update verification refuse |
[Settings] |
RestApiCertificateFile / PrivateKeyFile, MetricsServerCertificateFile / PrivateKeyFile, WebServicesCertificateFile / PrivateKeyFile
|
The listener starts without TLS, or does not start |
[Database] |
PostgreSQLSslRootCert |
PostgreSQL TLS verification fails |
Leave the [Database] connection keys alone. They name a server, not a path.
| Value | Where | Repaired by |
|---|---|---|
InstallLocation |
HKLM\SOFTWARE\hMailServer in the 32-bit view
|
Step 5, by hand |
Service ImagePath
|
HKLM\SYSTEM\CurrentControlSet\Services\hMailServer |
Step 6, /Register
|
LocalServer32 (79 keys) and InprocServer32 (15) |
HKCR\CLSID\... |
Step 6, /Register
|
TypeLib win64 and HELPDIR
|
HKCR\TypeLib\... |
Step 6, /Register
|
InstallLocation, UninstallString, DisplayIcon
|
HKLM\...\Uninstall\hMailServer_is1 |
Nothing. See step 11 |
The 32-bit view is not a mistake and not optional. The server reads that value
through KEY_WOW64_32KEY (Common/Util/Registry.cpp:40), and the installer
writes it there for the same reason
(hmailserver/installation/section_registry.iss). Writing the 64-bit view
changes nothing and looks like it worked.
Nine places hold a path an administrator typed. None of them is rewritten by anything, and there is no function that enumerates them.
| Table and column | What it is |
|---|---|
hm_sslcertificates.sslcertificatefile, .sslprivatekeyfile
|
Certificate and key files |
hm_domains.domaindkimprivatekeyfile, .domaindkimsecondaryprivatekeyfile
|
DKIM signing keys |
hm_tcpipports.portclientcertificatecafile |
The CA bundle for inbound client certificates |
hm_settings row backupdestination
|
Where backups are written |
hm_settings rows avclamwinexec, avclamwindb
|
ClamWin's scanner and database |
hm_settings row customvirusscannerexecutable
|
An external scanner command line |
hm_inisettings |
The whole [Settings] section, mirrored since schema 6011 |
hm_archiveindex.archivepath |
One row per archived copy |
hm_quarantine.quarantinefilename |
Held messages |
hm_rule_actions.actionfilename |
A rule that runs a program or writes a file |
hm_messages.messagefilename |
Relative since 5.4; see step 8 |
Nothing in this runbook may run against a live server. Stop it, and confirm it is stopped, before anything is copied.
Copy, do not move. The old tree is the rollback.
Include Bin\hMailServerApiKeys.ini if it exists: the REST API key store lives
there (Common/Util/RestApiServer.cpp:2414), and no installer manifest mentions
it.
Grant the service account access to the new tree. The installer grants it to
NT SERVICE\hMailServer on the data, log and temp directories; a copy made by an
administrator will usually inherit different rights, and a server that cannot
write its log directory starts and then says nothing.
Edit <new root>\Bin\hMailServer.ini and change every key from step 1 whose
value was under the old root. Nothing else.
The file is read from the directory the running hMailServer.exe sits in when
one is there, and otherwise from the registry (Common/Util/Utilities.cpp:102),
so the copy you edit is the one the moved server will read.
From an elevated prompt:
reg add "HKLM\SOFTWARE\hMailServer" /v InstallLocation /t REG_SZ /d "<new root>" /reg:32 /f
/reg:32 is the whole of the point. See step 1.
From an elevated prompt, from the new Bin:
hMailServer.exe /Register
One command repairs the service's ImagePath
(ServiceManager.cpp:45 → ChangeServiceConfig), all 79 LocalServer32
registrations, the 15 InprocServer32 ones, and the type library's win64 and
HELPDIR values. It must run elevated, and it must run from the new tree - it
registers the path of the executable that runs it.
Start the service and read the application log.
A server whose anchors are stale reports Running and serves an empty
configuration. That failure is silent, and it is the one this whole document
exists to prevent: build/preflight-tests.ps1 carries a check for it precisely
because it has happened. Confirm over COM or in the Control Panel that
Settings → Directories shows the new paths, that your domains are listed, and
that the log file you are reading is under the new log directory.
Only if Test message file locations reported full paths.
Run the Data Directory Synchronizer against the new data directory. It walks
the data directory and converts each absolute row to a partial name
(Tools/DataDirectorySynchronizer, MailImporter::ReplaceMessagePath_). It is
the supported converter; a UPDATE hm_messages SET ... is not, because the rows
are not uniform and the file layout is derived, not stored.
For each row from step 1's database table that pointed under the old root:
- SSL certificates. The Control Panel's certificate grid is read-only except for the passphrase, so each certificate must be deleted and re-added with its new file names, or set over COM.
- DKIM keys. Domain → DKIM, both the primary and, if used, the secondary.
- Client-certificate CA bundle. Advanced → TCP/IP ports, per port. A port set to require a client certificate refuses every client when its bundle cannot be loaded.
- Backup destination, ClamWin, custom scanner, rule actions. Each in its own page.
-
Archive index.
hm_archiveindex.archivepathholds one row per archived copy and is matched on the exact string by retention, legal hold and the address eraser. Do not bulk-rewrite it. If the archive directory moved, move the archive back or accept that pre-move rows point at the old location; there is no supported converter for this column.
- Send and receive a message.
- Complete a TLS handshake on every port that has a certificate.
- Connect on any port whose client-certificate policy is require.
- Run a backup to completion. It refuses outright when its destination is unwritable, which is the check you want.
- Run an event script, if you use them.
- Check the log directory is being written.
-
Add/Remove Programs still points at the old
unins000.exe. Do not editunins000.dat; it is a compiled record, and a hand edit produces an uninstaller that removes the wrong tree. The supported repair is to re-run the installer at the new root, which rewrites the uninstall metadata. - Start-menu shortcuts hold absolute targets and nothing repairs them. Re-create them, or re-run the installer.
- Message content. The old path appears inside messages the server itself wrote - a delivery report, for example, names the file it could not find. Those are historical records of what happened. Never rewrite message content, and be careful with any "search and replace across the installation" approach for exactly this reason.
Keep it, unreachable by the service, for at least one full backup cycle. Once it is deleted, the only rollback is the step 0 backup.
The Control Panel's Monitoring & troubleshooting → Diagnostics page (Monitoring and Health §16.8) has an Installation paths
section that lists the registry root, every [Directories] key, the derived
directories, and every path-shaped setting the running server holds, with the
ones that do not exist marked. It changes nothing; it is there so that the
inventory in step 1 can be read off a running server rather than assembled by
hand.
This came up as issue #158.
The short answer is that ProgramFolder is not the root of anything: it is one
of six independent absolute strings, and the registry holds a seventh copy that
the server actually uses to find its own INI file. From 6.3.0 a relative
value in the five non-program directories is resolved against the program folder,
so a new installation can be written to be movable; an existing installation's
absolute values are left exactly as they are, because rewriting a configured
server's paths during an upgrade is not something an upgrade may do.
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