Table of Contents
Stargate Pre-Requisites & Deployment Information¶
Pre-Requisites¶
Please ensure that all necessary preparatory steps have been completed before the HIN Gateway migration or new installation activities begin.
The following items must be available or confirmed before the installation:
-
Credentials will be delivered to you by HIN
- VM credential
- Keycloak credential
- Activation code
-
Export of private key
Info
Export of private keys is only for customers moving from existing MGW to a new HIN Gateway
- If you are working on a Windows machine that has access to the Mail Gateway VM via port 22, we can support you during the call in enabling the private key export from the MGW.
- If you do not have access to such a machine, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740) to help you establish a support connection via System Administration → Support Connection → Connect.
- Download latest version of VM image
- Firewall requirements for WireGuard.
Configure the WireGuard port 19818 (TCP/UDP) in your firewall:
- Incoming and outgoing traffic
- Allow traffic: any-to-HIN Gateway and HIN Gateway-to-any
-
DHCP access should be available. For more information see "Installation Guidelines".
-
Backup requirements - see "Annex 1 - Backing up and restoring the appliance settings".
Info
Backup requirements is only for customers moving from existing MGW to a new HIN Gateway
- Confirmation that the existing MGW will not be deleted until acceptance has been completed.
Info
Keeping the existing MGW available till acceptance report have been completed is only for customers moving from existing MGW to a new HIN Gateway
- Access to DNS, mail server connectors, transport rules, and relay settings.
Deployment Information¶
Installation Options¶
- VM image installation:
🖨️
You can get this documentation printed or saved as PDF, please visit our Print page view.
Exchange Integration¶
- Exchange integration - Configure Microsoft Exchange (Online and On-Premises) connectors and transport rules to route mail through Stargate
Server Requirements¶
| Minimum | Recommended | |
|---|---|---|
| CPU, Cores | 4 | 6 |
| RAM, GB | 8 | 12 |
| SSD, GB | 60 | 60 |
Common Requirements¶
- Root access: Must be run as root or with
sudo - Supported distributions:
- RHEL 8, 9 and 10 compatible distributions such as Alma Linux, Rocky Linux, CentOS Stream
- Ubuntu 22 and 24
- Debian 11, 12 and 13
- Real IPv4 address
- Valid DNS records. Your domain must have:
- MX records pointing to your mail servers
- SPF record defining allowed sending networks
- Server must be able to resolve DNS (MX, SPF, A records)
- Used for mail routing and SPF-based network allowlisting
Inbound Network Access (firewall must allow)¶
Firewall note
Depending on your firewall or NAT configuration, you may need to explicitly allow traffic for the required ports. Refer to your firewall and NAT documentation for details.
The VM must be able to accept incoming connections on the required service ports and send responses back to the requester. With a stateful firewall (such as iptables using conntrack), return traffic is automatically allowed by the ESTABLISHED,RELATED rules.
Example iptables configuration:
# Allow return traffic for established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow inbound TCP connections to the open ports
iptables -A INPUT -p tcp -m multiport --dports 25,8084,19818 -j ACCEPT
# Allow outbound TCP connections to the open ports
iptables -A OUTPUT -p tcp -m multiport --dports 25,8084,19818 -j ACCEPT
# Allow inbound UDP port 19818 for Wireguard
iptables -A INPUT -p udp --dport 19818 -j ACCEPT
# Allow outbound UDP port 19818 for Wireguard
iptables -A OUTPUT -p udp --dport 19818 -j ACCEPT
# Additional Services that VM shall be able to reach
# DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
# NTP
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT
# HTTP
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
# HTTPS
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
| Port | Protocol | Purpose |
|---|---|---|
25 |
TCP | SMTP - receiving mail from external servers |
8084 |
TCP | HTTP - seal callback from remote sealer service |
19818 |
UDP+TCP | WireGuard - encrypted tunnel for agent-to-agent communication. Read our Security Assessment WireGuard |
Inbound VM Access (your administrative machine to the HIN Gateway VM)¶
Info
These firewall rules should be applied only between your administrative machine and the HIN Gateway VM. There is no need to expose these ports to the Internet.
| Port | Protocol | Purpose |
|---|---|---|
80 |
TCP | Redirects HTTP traffic to HTTPS |
443 |
TCP | Used to manage the HIN Gateway through the web dashboard |
8180 |
TCP | Used by Keycloak to authenticate users for the HIN Gateway dashboard |
8190 |
TCP | Optional. Required for troubleshooting and viewing logs |
22 |
TCP | Optional. Required for troubleshooting and modifying configuration |
Outbound Network Access (server must reach)¶
| Destination | Port | Protocol | Purpose |
|---|---|---|---|
| hub.docker.com | 443 |
TCP | Docker image registry |
| mxengine-dev.k8s.vereign-cdn.com | 443 |
TCP | Remote sealer service |
| smimekeys-ca-dev.k8s.vereign-cdn.com | 443 |
TCP | S/MIME CA service |
| loki.example.com | 443 |
TCP | Log shipping (Alloy → Loki, optional) |
| Update Server of alpine, almalinux, etc. | 80 |
TCP | Various Update servers |
| Destination mail servers | 25 |
TCP | Outbound mail delivery (via MX lookup) |
| Standard DNS queries and responses | 53 |
UDP + TCP | DNS resolve |
| NTP servers | 123 |
UDP | NTP synchronizes the clocks of computers, servers, network devices, and virtual machines with accurate time sources |
Contact us¶
Support
For any questions or issues related to the deployment and operation of the HIN Mail (Stargate) appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
Installation Guides
HIN Mail Gateway - Technical Installation Process¶
Tip
Technical Installation Process for Single-Domain Mail Architecture with Microsoft 365
Introduction¶
This document provides a comprehensive guide to the technical installation and migration process to the new HIN Gateway ("Stargate Appliance"). It applies to Microsoft 365 mail architectures that use a single trusted domain.
The guide is intended for HIN customers, IT administrators and system engineers who are responsible for deploying and configuring the new HIN Gateway, and for migrating from the existing Mail Gateway (MGW) to the new solution.
The HIN Gateway is a secure email gateway solution that enables trusted, encrypted and policy-driven communication within the HIN Trust Circle. It acts as a central intermediary between internal email infrastructures and external communication partners, ensuring that all email traffic is transmitted securely, complies with the organisation's policies and meets HIN's security standards.
Overview of the mail flow¶
- Incoming emails are routed via the HIN Gateway, where they are validated, decrypted (if necessary) and checked against trust and security policies before being forwarded to the internal mail server.
- Outgoing emails are sent from internal systems to the HIN Gateway, where encryption, routing and policy enforcement are applied before they are transmitted to external recipients.
- Communication between HIN gateways is secured by peer certificates and WireGuard tunnels, ensuring trusted communication between domains.
Installation and migration process¶
The structured, step-by-step procedure described in this document covers the following points:
- Preparation and fallback planning
- Installation and configuration of the HIN Gateway
- Domain activation and certificate validation
- Mail server integration and routing configuration
- Testing, transition to production and post-migration validation
- Decommissioning of the existing MGW
HIN's objective in this process is to ensure a secure, smooth and fully validated migration that causes minimal disruption to operations and guarantees the uninterrupted continuity of email services.
Frequently asked questions¶
Can I perform the installation and migration on my own?
Yes, the installation and migration can be completed entirely by the customer, except for "Step 1.3 - Export private key(s)".
For security reasons and to keep your private key safe, you must contact HIN Support or join the planned migration call to receive the code required to export the private key from the currently operating Mail Gateway.
If the installation and migration cannot be completed successfully, please join the planned support call with our engineers.
Will there be any outage in email delivery during the migration?
Between "Step 1.5 - Shutdown existing MGW VM" and "Step 18 - Configure mail server", all emails will be queued on the mail server. Once "Step 18 - Configure mail server" has been completed, the queued emails will be sent out or delivered to the mailbox.
Will any emails be lost during the installation and migration?
No, no emails will be lost during the installation and migration.
Overview of the installation steps¶
| Step | Topic | Responsibility |
|---|---|---|
| 0 | Check prerequisites | Customer |
| 1.1 | Smoke test | Customer |
| 1.2 | Backing up the existing MGW | Customer |
| 1.3 | Export private key(s) | Customer / HIN |
| 1.4 | Contingency plan / fallback scenario | Customer |
| 1.5 | Shutdown existing MGW VM | Customer |
| 2 | WireGuard | Customer |
| 3 | Select target VM | Customer |
| 4 | Load VM image | Customer |
| 5 | Network connection to the VM | Customer |
| 6 | Access via the browser | Customer |
| 7 | Enter activation code | Customer |
| 8 | Mesh network setup | Customer |
| 9 | Establishing secure mesh network | Customer |
| 10 | Login to Keycloak | Customer |
| 11 | Update password | Customer |
| 12 | Update account information | Customer |
| 13 | Initial configuration and domain setup | Customer |
| 14 | Configure mail transport | Customer |
| 15 | Configure whitelist headers | Customer |
| 16 | Peer certificates | HIN |
| 17 | Validate peer certificates | Customer |
| 18 | Configure mail server | Customer |
| 19 | Test prior to switchover | Customer |
| 20 | Validation after switchover | Customer |
| 21 | Take existing MGW out of service | Customer |
| 22 | Change the password of the VM | Customer |
| Annex 1 | Backing up and restoring the appliance settings | Customer |
Detailed steps¶
Step 0 - Check prerequisites¶
Please ensure that all necessary preparatory steps have been completed before the HIN Gateway migration activities begin.
The following items must be available or confirmed before the installation:
-
Credentials will be delivered to you by HIN
- VM credential
- Keycloak credential
- Activation code
-
Export of private key
- If you are working on a Windows machine that has access to the Mail Gateway VM via port 22, we can support you during the call in enabling the private key export from the MGW.
- If you do not have access to such a machine, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740) to help you establish a support connection via System Administration → Support Connection → Connect.
- Download latest version of VM image
- Firewall:
- Allow traffic: any-to-HIN Gateway and HIN Gateway-to-any
- WireGuard, please refer to Server Requirements - Inbound Network Access:
- Configure the WireGuard port
19818(TCP/UDP) in your firewall- Incoming and outgoing traffic
- Configure the WireGuard port
- WireGuard, please refer to Server Requirements - Inbound Network Access:
- Allow traffic: your administrative machine-to-HIN Gateway VM
- Installation requirements:
- HTTPS port
443- Incoming and outgoing traffic
- Keycloak port
8180- Incoming and outgoing traffic
- HTTPS port
- Troubleshooting requirements (optional needed to see logs, modify all parameters):
- SSH port
22- Incoming and outgoing traffic
- Dozzle port
8190- Incoming and outgoing traffic
- SSH port
- Installation requirements:
- Allow traffic: any-to-HIN Gateway and HIN Gateway-to-any
- DHCP access should be available for "Step 5 - Network connection to the VM" (recommended).
- Backup requirements - see "Annex 1 - Backing up and restoring the appliance settings".
- Confirmation that the existing MGW will not be deleted until acceptance has been completed.
- Access to DNS, mail server connectors, transport rules, and relay settings.
Why WireGuard?
The WireGuard port fulfils two important functions:
- The HIN Gateway uses this port to obtain peer certificates from the HIN CA.
- It uses this port to establish a secure tunnel to other HIN Gateways, through which secure data exchange (e.g. email traffic) takes place.
Private key export
If you are working on a Windows machine that has access to the Mail Gateway VM via port 22, we can support you during the call in enabling the private key export from the MGW.
If you do not have access to such a machine, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740) to help you establish a support connection via System Administration → Support Connection → Connect.
Step 1.1 - Smoke test¶
Send a test email to the following recipients, where you have access to the mailbox to check correct receipt:
- An HIN email address or HIN community domain of yours, for example:
user@hin.ch - An email address outside of the HIN community, for example:
user@bluewin.ch
Verify that both emails are delivered successfully, including subject, content and attachment (if sent).
Step 1.2 - Backing up the existing MGW¶
Create a backup of the existing MGW appliance and ensure that the VM is retained until the migration has been successfully completed and formally accepted. For more information, see "Annex 1 - Backing up and restoring the appliance settings".
Check current MGW routing configuration
Before shutting down the existing MGW, check the following configuration values and note them down. You will likely need them later when configuring the HIN Gateway:
- Log in to the MGW and go to "Mail System → Outgoing server" and check whether anything is configured there.
- For each domain hosted on the MGW, go to
Mail System → <domain> → Forwarding serverandMail System → <domain> → Send ALL outgoing mails from this domain to the following SMTP server, and record the current values.

MGW header check
If you use the Header check option in the MGW, note down the configured value as well. You can set up the same header check later in the HIN Gateway.
Step 1.3 - Export private key(s)¶
HIN assistance required
An unlock code is required for this step. The code is provided by a HIN Support Engineer.
If you would like to continue the installation on your own, please contact HIN Support to request the unlock code. Otherwise, the unlock code will be provided during the planned migration call.
- Log into the existing MGW webGUI.
- Open "Mail System".

- Run the application by clicking on
HIN_Migration-Tool_v*.exeif you want to install it yourself. Alternatively, you can wait until the migration call, where the support engineer will assist you with the installation.

- Enter the unlock code that the support engineer provides to you.

- Select "Enable export".

- Enter the MGW IP address.

- Wait for confirmation.

- Select the trusted domain in the MGW webGUI.

- Scroll down and select the managed fingerprint.

- Scroll down to the "PKCS12 download" category (you may optionally enter a password to encrypt the key). Press "Download PKCS12" and save the
*.p12file on the computer.

- Return to the
HIN_Migration-Tool_v*.exeapplication and disable the Export button.

Step 1.4 - Contingency plan / fallback scenario¶
Rollback scenario - if a rollback is required:
- Stop the new HIN Gateway.
- Power on the existing MGW.
- Verify that inbound and outbound email traffic is functioning correctly via the existing MGW.
Step 1.5 - Shutdown existing MGW VM¶
Shut down the existing MGW VM.
Warning
This step will interrupt the mail flow. During the interruption, emails will be queued on the mail server and delivered after the installation has been completed (see "Step 18 - Configure mail server").
Step 2 - WireGuard¶
Ensure you have configured the WireGuard port 19818 (TCP/UDP) in your firewall:
- Incoming and outgoing traffic
- Allow traffic: any-to-HIN Gateway and HIN Gateway-to-any
Step 3 - Select target VM¶
Select one of the available virtual images and provision it as described in the installation guide on the HIN Gateway service page:
Info
For security and supportability reasons, ensure that your hypervisor is not running an end-of-life version. The HIN Gateway appliance is supported on the latest hypervisor release and the immediately preceding major version.
- VM Image Installation:
- Configuration of Microsoft Exchange
Step 4 - Load VM image¶
Upload the selected VM image to your hypervisor.
Step 5 - Network connection to the VM¶
Ensure that the VM has a network connection and that a static IP address has been assigned to it.
Option A: Configure the IP address of the virtual machine directly in the hypervisor you are using.
Option B: You can configure your router's DHCP server to always assign the same IP address based on the VM's MAC address.
Option C: Log in locally via the VM console and manually configure a static IP address. NOTE: The VM image runs an automatic installation during the first boot. If the network is not configured at this stage, the installation will fail because the server’s IP address cannot be determined.
Add an IP address on Linux:
-
Run the "nmtui" command in the console
-
Use the arrow keys to navigate, then press "Enter" to select the "Ethernet connection" for which you want to change the IP address.

- Navigate to "IPv4 Configuration" and change the setting from "Automatic" to "Manual".

- Use the arrow keys to navigate to the fields where you can enter the IP address, gateway, and DNS server. Then select "OK".

-
After saving the IP address configuration, run the following command in the console:
Network must be configured before first boot
The VM image runs an automatic installation on first boot. If the network is not yet configured (no IP address assigned via DHCP or static config), the installation will fail because the server IP cannot be detected.
If this happens, configure the network manually, then run:
cd /root/stargate-deployment/docker-compose
./scripts/purge.sh
# Update configuration with a new ip, by editing it with nano
# SERVER_STATIC_IP=<NEW IP>
nano customer-config.sh
# OR use sed
# sed -i 's/old IP/new IP/g' customer-config.sh
./scripts/install.sh
The install script will auto-detect the server's IP from the default route. Any reachable IP (public or private) is sufficient - the actual public endpoint is configured later through the dashboard.
Tip
If you used Option C and configured the network manually, you must run the following commands:
cd /root/stargate-deployment/docker-compose
./scripts/purge.sh
# Update configuration with a new ip, by editing it with nano
# SERVER_STATIC_IP=<NEW IP>
nano customer-config.sh
# OR use sed
# sed -i 's/old IP/new IP/g' customer-config.sh
./scripts/install.sh
The installation script will automatically detect the server’s IP address from the default route. Any reachable IP address, whether public or private, is sufficient. The actual public endpoint is configured later through the dashboard.
After the scripts have completed successfully, proceed to "Step 6 – Access via the browser"
Question
If you do not have the HIN admin credentials, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740). Please refer to Support Section.
Step 6 - Access via the browser¶
Open a browser and enter the IP address configured for the VM. You should see the initial setup screen.
Step 7 - Enter activation code¶
Select your preferred language and enter the activation code that you received via email from HIN. Click on "Next".
I do not have an activation code
If you do not have the activation code, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740). Please refer to Support Section.
Step 8 - Mesh network setup¶
Verify the mesh network configuration:
- IP address - The public IP of the outgoing traffic (auto-detected).
- Transport - The transport protocol (default:
tcp). - Port - The WireGuard port (default:
19818).
What is public IP?
This is an IP address that Machine will use to be accessible via internet.
This is not internal Machine IP address after Firewall or NAT, e.g. 10.0.0.0/8, 172.16.0.0/12 or 192.168.0.0/16.
Confirm that the values are correct and click "Next".
Step 9 - Establishing secure mesh network¶
The system will now establish the secure mesh network connection. This step connects the HIN Gateway to the Iris Agent and synchronises certificates.
Wait until the process completes. The status indicators will show "Up" when the connection is successfully established. Click "Finish".
If the connection fails
If the Iris Agent or certificate synchronisation status remains "Down":
- Verify that port
19818(TCP/UDP) is open in your firewall (see "Step 2 - WireGuard"). - Verify that the IP address in "Step 8 - Mesh network setup" is correct and reachable from the internet.
- Restart the process or contact HIN Support by email or phone (support@hin.ch / 0848 830 740).
Step 10 - Login to Keycloak¶
Warning
Port 8180 needs to be open for Keycloak. It does not need to be accessible from the internet to the whole world. Rather, it should be accessible between your administrative machine and the VM you are installing. Otherwise, you will not be able to connect to Keycloak and proceed with the installation.
What to do if I see a connection error
Please check if port 8180 is open from your machine to the VM. As soon as you update the configuration, go back to the UI at https://<VM IP address> and click the "Login" button.
Once the mesh network is established, you will be redirected to the Keycloak login page. Enter the username and password received from HIN.
Question
If you do not have these login details, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740). Please refer to Support Section.
Step 11 - Update password¶
On first login, you will be prompted to change your password. Enter a new secure password and confirm it.
Step 12 - Update account information¶
Complete your account profile by entering your first name and last name. The email address is pre-filled. Click "Submit" to continue.
Step 13 - Initial configuration and domain setup¶
On this screen, configure your initial settings:
- Verify that all your current trusted domain(s) within the HIN Community are displayed correctly.
- Select which trusted domain(s) should be Enabled to obtain peer certificates from the HIN Certification Authority (HIN CA).
- Indicate for which domain(s) the
sec.<domain>prefix is already configured ("Use sec-prefix").
How to check if my domain is set up with a Security Prefix?
You can open our online tool in your browser: https://trust.hin.ls-infra.me/, enter sec.<domain>, and click the Check button. If you see the message:
✅ This domain is encrypted.
Then your domain is set up with a Security Prefix, and you have to enable the Use sec-prefix option.
- Verify that the organization name and domain owners are correct.

- Import the existing S/MIME certificate file (
.p12/.pfx) from the existing MGW:- Expand the domain and select the P12/PFX File option.
- If no password has been set for the certificate file, leave the password field empty.
- Click "Import Certificate".
- After the certificate has been imported, the message Certificate imported successfully is displayed.
- Click "Save Configuration" at the end of the page to save the changes.
Warning
- At least one domain must be Enabled to continue with the onboarding process. The "Save configuration" button will only become active once this requirement is met.
- If you notice that not all trusted domains are displayed or that the organisational information is incorrect, please contact HIN Support by email or phone (support@hin.ch / 0848 830 740).
Import your existing private key
If you do not import the private key from your existing MGW, a new key will be issued. This may result in messages not being decryptable for up to 6 hours, which could lead to data loss.
Step 14 - Configure mail transport¶
On this screen, configure your mail transport settings for the secure mail relay setup.
The following settings are available:
| Setting | Description |
|---|---|
| Mail server host name | The FQDN of this mail gateway instance (e.g. mail.example.com). |
| Mail server IP addresses | The public IP address(es) of this server. Add additional IPs if the server is reachable on multiple addresses. |
| Domains | Each domain that this gateway handles, along with its relay host (the internal mail server to which inbound mail is delivered). |
| Default relay host | The default SMTP relay for outbound delivery. |
Under the Advanced section, you can optionally configure:
| Setting | Description |
|---|---|
| Configure TLS | TLS certificate settings for SMTP connections. |
| Content filter | The internal content filter endpoint (default: mxengine:1587). |
| Trusted networks | Additional networks allowed to relay through this gateway. |
Additional actions:
- Add additional domains by clicking "Add domain", if required.
- Expand the Advanced section to fine-tune mail transport parameters.
Note
Ensure that all relay host and domain configurations are correct before proceeding.
Once the configuration has been reviewed and completed, click "Apply configuration" to continue.
Step 15 - Configure whitelist headers¶
Click "Domains", then select "Whitelist headers".
Enter the key exactly as configured in the mail server.
Step 16 - Peer certificates¶
Peer certificates are issued by the HIN Certification Authority (HIN CA) for enabled domains.
Once the onboarding is complete, navigate to the Peer certificates section in the dashboard and click the "Sync certificates" button to synchronise your peer certificates from the HIN CA.
Step 17 - Validate peer certificates¶
Ensure that your domain has received its policy-based peer certificate under "Domains". The status of each domain must be "Good".
Question
Contact HIN Support by email or phone (support@hin.ch / 0848 830 740) if you encounter any issues.
Step 18 - Configure mail server and HIN Gateway¶
If you followed the recommended approach by exporting the private key, importing it into the HIN Gateway, and keeping the same IP address as the existing MGW, no changes are required on the email server.
Otherwise, configure your mail server or the associated components so that traffic is routed via the new HIN Gateway. Check and update the following settings, if required:
Email server¶
- SMTP relay / smart host
- Connectors
- Transport rules
- Routing domains
See Exchange Integration for detailed instructions.
HIN Gateway config¶
-
Go to the
Settingspage and, for each domain, add a Relay host using the value you recorded from the MGW'sForwarding serverfield in "Step 1.2 - Backing up the existing MGW".

-
On the same
Settingspage, set the Default relay host. -
If you are using Microsoft 365 / Exchange Online, add its published outbound IP ranges to
Settings→Trusted networksso the HIN Gateway trusts and relays mail coming from Exchange Online:
Step 19 - Test prior to switchover¶
Repeat the "Step 1.1 - Smoke test". In addition to the smoke test, please test and confirm the following:
Outgoing:
- Verify that the mail server is configured to send emails to the HIN Gateway using an SMTP relay or Exchange connector.
- Verify that the HIN Gateway can send emails to recipients outside the HIN Community.
- Verify that the HIN Gateway can send emails to recipients inside the HIN Community via WireGuard.
Incoming:
- Verify that encrypted emails can be received from the HIN Community via WireGuard. A sender from the
hin.chdomain is the easiest test path. - Verify that encrypted emails can be received from the HIN Community via SMTP using S/MIME.
- Verify that replies from senders outside the HIN Community to an initial secure email (HIN Mail-SEAL) can reach the HIN Gateway.
- Verify that plain-text emails can be received from external senders outside the HIN Community.
Step 20 - Validation after switchover¶
Confirm:
- Emails delivered
- Encryption applied
- No delays or bounces
- Logging successful
Complete the Acceptance Report and return it to your HIN representative.
Step 21 - Take existing MGW out of service¶
Warning
Do not delete the existing MGW VM immediately - keep it safe until everything is up and running.
- Ensure there is no active traffic - check:
- No domains are pointing to the MGW (DNS, SMTP, connectors).
- No emails are being forwarded via the old appliance.
- Archive logs - export and save:
- Email logs
- Security/audit logs
- Required for compliance and troubleshooting
- Clean-up (optional) - remove:
- Firewall rules
- DNS entries
- Routing configurations that reference the existing MGW
Step 22 - Change the password of the VM¶
Please make sure that the VM credentials which were provided to you initially are changed to your own defined password, and keep them in a secured and safe place.
Annex 1 - Backing up and restoring the appliance settings¶
To back up or restore the settings of your HIN appliance, click the "Administration" menu in the web administration portal.
Backing up settings¶
Before you create a backup of the current HIN appliance settings, you must set a backup password. This password is required if you need to restore the backup later.
- To set or change the backup password, click "Change Password".
- To create and download a backup file, click "Download".
Changing the backup password¶
To change the password for future backups, click "Change Password".
Note
The new password only applies to backups created after the password has been changed. Existing backup files remain protected by the password that was set when they were created.
Restoring settings¶
To restore appliance settings from a backup file, click "Import Backup File...".
In the dialog window, select the required backup file and enter the password associated with that backup. The appliance settings will then be restored from the selected backup file.
Backup using SCP¶
The MGW supports backing up the appliance via SCP.
To use this option, the public key of the system that will access the MGW must be stored under "Backup using SCP". The backup is generated automatically every day at midnight and is stored on the MGW as backup.tgz.
Using the configured public key, the backup file can be retrieved via SCP with the operating system user backup. A typical SCP command to retrieve the backup file is:
This command downloads the file backup.tgz from the MGW to the current local directory.
Note
If you enter a new public key, the existing key will be replaced.
Technical configuration and Integration
Applications overview¶
Applications¶
- smimekeys-client - S/MIME keys client service (port
8081) - policy - Policy service (port
8082) - irisagent - IRIS Agent service (port
8083, WireGuard:19818/udp,19818/tcp) - mxengine - MX Engine service (port
8084, SMTP:1587) - stalwart - Stalwart MTA mail server (port
25,10026) - clamav - ClamAV antivirus; scans mail at Stalwart's SMTP DATA stage via the milter protocol (port
7357) - mtaconf - MTA configuration daemon (API:
8080) - dashboard - Web-based admin UI for onboarding, domain management, and monitoring (port
443) - policy-sync - Syncs OPA/Rego policies from Git repository to database (runs continuously)
Infrastructure¶
- PostgreSQL - Database (port
5432) - Vault - Secrets management (internal port
8200, not published to the host) - MinIO - S3-compatible storage (API on host port
9000; console not published to the host) - Keycloak - Identity provider and OIDC authentication (port
8180) - APISIX - API gateway with OIDC bearer auth (port
9080) - NATS - Inter-service messaging (triggers Stalwart reloads from dashboard)
Init Containers¶
- vault-init - Initializes and unseals Vault on first run
- seaweedfs-init - Creates the S3 bucket
- apisix-init - Generates APISIX config from template
- keycloak-init - Sets initial admin password
Monitoring¶
- node-exporter - Host metrics for Prometheus (port
9100) - version-collector - Collects app versions from
/livenessendpoints for node-exporter - Alloy - Log collector for Loki (ships app logs)
- Dozzle - Real-time container log viewer (port
8190, HTTPS, behind Keycloak SSO via oauth2-proxy; optional, enabled withDOZZLE_ENABLED) - oauth2-proxy - OIDC relying party that authenticates Dozzle access against Keycloak (starts together with Dozzle)
See Monitoring and Logs for detailed configuration and usage.
Architecture overview¶
VM Architecture overview¶
Monitoring and Logs¶
Stargate includes built-in monitoring and log collection services that run alongside the application containers.
Components¶
| Service | Port | Purpose |
|---|---|---|
| node-exporter | 9100 |
Host-level metrics (CPU, memory, disk, network) for Prometheus |
| version-collector | - | Collects app versions from /liveness endpoints |
| Alloy | 12345 |
Docker log collector - ships container logs to Loki |
| Loki | 3100 (internal) |
Local log aggregation backend |
| Dozzle | 8190 |
Web-based container log viewer (HTTPS, Keycloak SSO; optional) |
| oauth2-proxy | 8190 |
OIDC relying party that authenticates Dozzle access (with Dozzle) |
Dozzle - Local Log Viewer¶
Dozzle provides a web-based UI to view real-time logs from all Stargate containers. It is optional and enabled by setting DOZZLE_ENABLED="true" in customer-config.sh.
Access is protected by Keycloak: an oauth2-proxy sits in front of Dozzle and requires the same login as the dashboard (the stargate realm). Dozzle itself is not exposed directly.
Access: open https://<SERVER_IP>:8190 in a browser and sign in with your HIN Gateway (Keycloak) credentials.
Note
Port 8190 (HTTPS) must be reachable from your network. If you restrict access by IP or firewall, allow 8190/tcp as you do for the dashboard and Keycloak.
Logs are organized by service. By selecting a specific service, you can view its corresponding log entries and details.
Grafana Alloy - Log Forwarding¶
Grafana Alloy collects logs from all Stargate application containers and writes them to the local Loki instance. Optionally, logs can also be forwarded to a remote Loki-compatible endpoint for centralized monitoring.
How it works¶
- Alloy discovers Stargate containers via the Docker socket
- Logs are always written to the local Loki instance (used by the dashboard for log export)
- If a remote Loki URL is configured, logs are additionally forwarded to that endpoint
Configuring remote log forwarding¶
From the HIN Gateway dashboard, navigate to the Settings page. Under the Grafana Alloy section, enter the Loki push URL of your remote log collection server:
The URL should follow the standard Loki push API format:
Leave the field blank to disable remote log forwarding.
Note
Changes take effect within 1 minute (Alloy polls the dashboard configuration on that interval). No container restart is required.
Requirements on the remote side¶
Your remote Loki endpoint must be reachable from the Stargate server over HTTPS (port 443). If you use IP-based allowlisting on your ingress, add the Stargate server's public IP.
Prometheus Metrics¶
Stargate exposes Prometheus-compatible metrics endpoints from its application containers. These can be scraped by any Prometheus-compatible server for centralized metrics collection.
Available endpoints¶
| Service | Port | Path |
|---|---|---|
| smimekeys-client | 2113 |
/metrics |
| irisagent | 2114 |
/metrics |
| policy | 2115 |
/metrics |
| mxengine | 2116 |
/metrics |
| node-exporter | 9100 |
/metrics |
| APISIX | 9091 |
/apisix/prometheus/metrics |
Scrape configuration¶
Add the Stargate server as a target in your Prometheus configuration. Example for a single instance:
scrape_configs:
- job_name: 'stargate-<name>-smimekeys'
static_configs:
- targets: ['<STARGATE_IP>:2113']
labels:
environment: 'stargate-<name>'
service: 'smimekeys-client'
metrics_path: /metrics
- job_name: 'stargate-<name>-irisagent'
static_configs:
- targets: ['<STARGATE_IP>:2114']
labels:
environment: 'stargate-<name>'
service: 'irisagent'
metrics_path: /metrics
- job_name: 'stargate-<name>-policy'
static_configs:
- targets: ['<STARGATE_IP>:2115']
labels:
environment: 'stargate-<name>'
service: 'policy'
metrics_path: /metrics
- job_name: 'stargate-<name>-mxengine'
static_configs:
- targets: ['<STARGATE_IP>:2116']
labels:
environment: 'stargate-<name>'
service: 'mxengine'
metrics_path: /metrics
- job_name: 'stargate-<name>-node'
static_configs:
- targets: ['<STARGATE_IP>:9100']
labels:
environment: 'stargate-<name>'
service: 'node-exporter'
metrics_path: /metrics
Replace <STARGATE_IP> with the server's public or private IP and <name> with a deployment identifier (e.g., prod, customer-name).
Tip
The environment and service labels enable filtering in Grafana dashboards across multiple Stargate instances.
Firewall requirements¶
The metrics ports (2113-2116, 9100) must be reachable from your Prometheus server. If you restrict access by IP, add your monitoring server's IP to the firewall rules.
Node Exporter¶
The node-exporter service exposes standard host-level metrics (CPU, memory, disk I/O, network) on port 9100. It also includes a textfile collector that exposes custom metrics from the version-collector sidecar (application version information).
Summary of exposed ports¶
| Port | Service | Protocol | Purpose |
|---|---|---|---|
8190 |
Dozzle (via oauth2-proxy) | HTTPS | Authenticated log viewer UI (Keycloak SSO) |
9100 |
node-exporter | HTTP | Host metrics (Prometheus) |
2113 |
smimekeys-client | HTTP | App metrics (Prometheus) |
2114 |
irisagent | HTTP | App metrics (Prometheus) |
2115 |
policy | HTTP | App metrics (Prometheus) |
2116 |
mxengine | HTTP | App metrics (Prometheus) |
9091 |
APISIX | HTTP | Gateway metrics (Prometheus) |
Exchange Integration with Stargate¶
This guide explains how to configure Microsoft Exchange (Online and On-Premises) to route mail through the Stargate gateway for S/MIME signing and encryption.
Overview¶
Stargate acts as a mail relay between external mail servers and your Exchange environment. Two integration patterns are supported:
Pattern A - Stargate as primary MX (recommended for inbound S/MIME processing):
flowchart LR
I1 --> mx15 --> mx20
EO --> TR --> OC --> Stargate --> I2
I1["Internet"]
I2["Internet"]
mx15["Stargate (MX priority 15)"]
mx20["Exchange Online (MX priority 20)"]
EO["Exchange Online"]
TR["Transport Rule"]
OC["Outbound Connector"]
Stargate
Pattern B - Exchange Online as primary MX with transport rules:
flowchart LR
I1 --> EO --> TR --> C --> S1 --> EO
E2 --> TR2 --> OC --> S2 --> I2
I1["Internet"]
I2["Internet"]
EO["Exchange Online"]
E2["Exchange Online"]
TR["Transport Rule"]
TR2["Transport Rule"]
OC["Outbound Connector"]
C["Connector"]
S1["Stargate"]
S2["Stargate"]
In both patterns, you need:
- DNS records pointing to the Stargate server
- Outbound connector - routes mail from Exchange to Stargate
- Inbound connector - accepts mail from Stargate into Exchange
- Transport rule - triggers the outbound connector for external recipients
Prerequisites¶
Before configuring Exchange, ensure:
- Stargate is installed and running (deployment instructions)
- You have the Stargate server's public IP address (referred to as
<STARGATE_IP>below) - You have the mail hostname of the Stargate server (referred to as
<MAIL_HOSTNAME>, e.g.mail.example.com) - You know your mail domain (referred to as
<YOUR_DOMAIN>, e.g.example.com) - You have Exchange admin access (Exchange Admin Center or on-premises Exchange Management Shell)
- DNS records are configured per the DNS Setup Guide (A, MX, SPF at minimum)
Part 1: DNS Setup¶
See the DNS Setup Guide for complete instructions on configuring A, MX, SPF, PTR, DMARC, and DKIM records.
At minimum, before proceeding with the Exchange configuration below, you need:
- A record:
<MAIL_HOSTNAME>pointing to<STARGATE_IP> - MX record:
<YOUR_DOMAIN>with Stargate at higher priority (lower number) than Exchange - SPF record:
ip4:<STARGATE_IP>andip4:<HIN_SEALER_IP>added to your domain's TXT record (see DNS Setup Guide - SPF for sealer IPs)
Part 2: Exchange Online Configuration¶
Step A: Create the Outbound Connector (Office 365 → Stargate)¶
This connector routes outbound mail from Exchange Online to the Stargate relay server.
-
Navigate to the Exchange Admin Center - Connectors
-
Click "+ Add a connector"
-
Connection from: Select "Office 365"
- Connection to: Select "Your organization's email server"
-
Click "Next"
-
Connector name: Enter a descriptive name, e.g.:
- Check "Retain internal Exchange email headers"
-
Click "Next"
-
Use of connector: Select "Only when I have a transport rule set up that redirects messages to this connector"
- Click "Next"
Tip
This is important - the connector won't route any mail by itself. It will only be used when triggered by the transport rule created in Step C.
- Routing: Select "Route email through these smart hosts"
- Enter the Stargate server IP address:
<STARGATE_IP> -
Click "+" to add it, then click "Next"
-
Security restrictions: Select "Any digital certificate, including self-signed certificates"
- Click "Next"
Note
Stargate's MTA (Stalwart) accepts opportunistic TLS on inbound connections. Selecting "any digital certificate" ensures connectivity even with self-signed certificates.
- Validation email: Enter a valid email address for your domain (e.g.
user@<YOUR_DOMAIN>) - Click "+", then click "Validate"
- Wait for validation to complete, then click "Next"
Tip
For validation to succeed, the Stargate server must be running and accepting mail on port 25.
-
Review the settings and click "Create connector"
-
On the confirmation screen, click "Done"
Step B: Create the Inbound Connector (Stargate → Office 365)¶
This connector accepts mail from the Stargate relay server into Exchange Online.
-
From the Connectors page, click "+ Add a connector"
-
Connection from: Select "Your organization's email server"
- Connection to: Shows "Office 365" (automatic)
-
Click "Next"
-
Connector name: Enter a descriptive name, e.g.:
- Check "Retain internal Exchange email headers"
-
Click "Next"
-
Authenticating sent email: Select "By verifying that the IP address of the sending server matches one of the following IP addresses that belong exclusively to your organization"
- Enter the Stargate server IP address:
<STARGATE_IP> - Click "+" to add it, then click "Next"
Note
This tells Exchange Online to trust mail from this specific IP address, bypassing additional spam/authentication checks for mail that has already been processed by Stargate.
-
Review the settings and click "Create connector"
-
Click "Done"
Verify Connectors¶
After creating both connectors, the Connectors page should show:
| Status | Name | From | To |
|---|---|---|---|
| On | Receive mail from Stargate relay server | Your org | O365 |
| On | From Office 365 to Stargate relay server | O365 | Your org |
Step C: Create the Transport Rule¶
The transport rule redirects all outbound mail through the Stargate outbound connector, except mail originating from Stargate itself (to prevent mail loops).
-
Navigate to Exchange Admin Center - Rules
-
Click "+ Add a rule" → "Create a new rule"
-
Rule name: Enter a descriptive name, e.g.:
- Apply this rule if: Select "The recipient..." → "is external/internal" → "Outside the organization"
- Click "Save"
Note
This condition ensures only outbound mail (to external recipients) is redirected through Stargate.
- Do the following: Select "Redirect the message to..." → "the following connector" → select the outbound connector created in Step A (e.g. "From Office 365 to Stargate relay server")
-
Click "Save"
-
Except if: Click "+" to add an exception
- Select "The sender..." → "IP address is in any of these ranges"
- Enter the Stargate server IP address:
<STARGATE_IP> - Click "Add", verify the IP is listed, then click "Save"
Warning
This exception is critical - it prevents mail loops. Without it, mail from Stargate arriving at Exchange Online would be redirected back to Stargate in an infinite loop.
- Review the rule summary. It should show:
- Apply this rule if: The recipient is located Outside the organization
- Do the following: Redirect the message to the connector "From Office 365 to Stargate relay server"
-
Except if: The sender IP address is in one of these ranges:
<STARGATE_IP> -
Click "Next", then "Next" again, then "Finish", then "Done"
-
Enable the rule: The rule is created in a disabled state. Click on the rule in the list and toggle "Enable or disable rule" to "Enabled"
Tip
Do not forget to enable the rule - it will not work until enabled.
Part 3: On-Premises Exchange Server Configuration¶
For on-premises Exchange Server (2016, 2019), the setup is similar but configured through the Exchange Management Console (EAC) or Exchange Management Shell (PowerShell).
Send Connector (On-Premises → Stargate)¶
Create a Send connector to route outbound mail through Stargate:
Exchange Management Shell (PowerShell):
New-SendConnector -Name "To Stargate Relay" `
-AddressSpaces "SMTP:*;1" `
-SmartHosts "<STARGATE_IP>" `
-SmartHostAuthMechanism None `
-DNSRoutingEnabled $false `
-SourceTransportServers "<YOUR_EXCHANGE_SERVER>"
Exchange Admin Center (GUI):
- Navigate to Mail flow → Send connectors
- Click + to create a new connector
- Name: "To Stargate Relay"
- Type: Select "Internet"
- Network settings: Select "Route mail through smart hosts", add
<STARGATE_IP> - Smart host authentication: Select "None"
- Address space: Add
*(all domains) or specific external domains - Source server: Select your Exchange transport server(s)
Receive Connector (Stargate → On-Premises)¶
Create or modify a Receive connector to accept mail from Stargate:
Exchange Management Shell (PowerShell):
New-ReceiveConnector -Name "From Stargate Relay" `
-Bindings "0.0.0.0:25" `
-RemoteIPRanges "<STARGATE_IP>" `
-TransportRole FrontendTransport `
-Usage Custom `
-AuthMechanism ExternalAuthoritative `
-PermissionGroups ExchangeServers
Exchange Admin Center (GUI):
- Navigate to Mail flow → Receive connectors
- Click + to create a new connector
- Name: "From Stargate Relay"
- Type: Select "Frontend Transport"
- Network adapter bindings: Leave default or bind to specific IP
- Remote network settings: Remove the default
0.0.0.0-255.255.255.255and add only<STARGATE_IP> - Authentication: Check "Externally Secured"
- Permission groups: Check "Exchange servers"
Transport Rule (On-Premises)¶
Create a transport rule to redirect outbound mail through the Send connector:
Exchange Management Shell (PowerShell):
New-TransportRule -Name "Relay outbound via Stargate" `
-SentToScope NotInOrganization `
-RouteMessageOutboundConnector "To Stargate Relay" `
-ExceptIfSenderIpRanges "<STARGATE_IP>"
Exchange Admin Center (GUI):
- Navigate to Mail flow → Rules
- Click + → "Create a new rule"
- Name: "Relay outbound via Stargate"
- Apply this rule if: "The recipient is located..." → "Outside the organization"
- Do the following: "Redirect the message to..." → "the following connector" → "To Stargate Relay"
- Except if: "The sender IP address is in..." → add
<STARGATE_IP>
Part 4: Stargate-Side Configuration¶
Automatic Configuration (Default)¶
By default, Stalwart automatically discovers where to deliver processed mail by looking up MX records for each domain configured via the dashboard's /mail page. It filters out its own hostname and uses the remaining MX entries as delivery targets.
This works when:
- Your domain has MX records pointing to both Stargate and Exchange
- Stargate has a higher-priority (lower number) MX record than Exchange
Manual Override via the dashboard¶
If you want all outbound mail from Stargate to go to a single Exchange endpoint (e.g. Exchange Online Protection), set the relay host through the dashboard's /mail page (e.g. [smtp.office365.com]). The dashboard sends the value to mtaconf's REST API and the daemon applies it to Stalwart.
Note
A single relay host sends all mail through one server and does not support per-domain routing. For multiple domains routing through different Exchange servers, use the per-domain relay map on the same dashboard page (configures sender_dependent_relayhost_maps under the hood) - see Multi-Domain Setup below.
Multi-Domain Setup¶
For setups with multiple domains and different Exchange servers (e.g. BALZ Informatik AG with 26 domains), use MX records for per-domain routing:
domain1.com MX 10 exchange1.domain1.com
domain1.com MX 20 stargate.domain1.com
domain2.com MX 10 exchange2.domain2.com
domain2.com MX 20 stargate.domain2.com
Each domain's MX records tell Stargate where to deliver processed mail for that specific domain.
Verify Stargate Configuration¶
After setup, verify the Stalwart configuration:
Check relay configuration¶
Check mail queue (should be empty when everything is working)¶
Send a test email and check logs¶
Troubleshooting¶
Mail not leaving Exchange Online¶
- Verify the transport rule is enabled (it is created in a disabled state)
- Check the rule conditions - it should apply to recipients "Outside the organization"
- Verify the outbound connector validation passed
- Check Exchange message trace in the Admin Center for delivery status
Mail loops (duplicate messages)¶
- Ensure the transport rule has the exception for the Stargate IP address
- Without this exception, mail from Stargate arriving at Exchange gets redirected back to Stargate
Stargate not accepting mail from Exchange¶
- Check port 25 is open on the Stargate server's firewall
- Verify SPF record includes the Stargate IP
- Check Stalwart logs:
docker logs stargate-stalwart
Exchange Online rejecting mail from Stargate¶
- Verify the inbound connector is configured with the correct Stargate IP
- Check that the Stargate IP hasn't changed
- Verify the connector is enabled (Status: On)
TLS Certificate Errors¶
Stargate uses opportunistic TLS with a self-signed certificate. The outbound connector in Exchange should be configured to accept "Any digital certificate, including self-signed certificates". If you see TLS-related errors:
- Verify the outbound connector security setting allows self-signed certificates
- For on-premises Exchange, ensure the Send connector does not require TLS (
-RequireTLS $false)
Validation fails during connector creation¶
The outbound connector validation requires:
- Stargate server is running and accepting connections on port 25
- The validation email address is valid for your domain
- Network path between Exchange Online and Stargate is open (no firewall blocking)
Quick Reference¶
| Component | Exchange Online Location | Purpose |
|---|---|---|
| Outbound Connector | Admin Center → Mail flow → Connectors | Route outbound mail to Stargate |
| Inbound Connector | Admin Center → Mail flow → Connectors | Accept mail from Stargate |
| Transport Rule | Admin Center → Mail flow → Rules | Trigger outbound connector for external recipients |
| DNS Record | Example | Purpose |
|---|---|---|
| A | mail IN A <STARGATE_IP> |
Point hostname to Stargate |
| MX (Stargate) | @ IN MX 15 mail.<YOUR_DOMAIN>. |
Inbound mail hits Stargate first |
| MX (Exchange) | @ IN MX 20 <DOMAIN>.mail.protection.outlook.com. |
Fallback / delivery target |
| SPF | ip4:<STARGATE_IP> and ip4:<HIN_SEALER_IP> added to existing TXT record |
Authorize Stargate and HIN sealer to send mail |
For the full DNS setup (including PTR, DMARC, DKIM, and multi-domain), see the DNS Setup Guide.
Stargate mail relay setup¶
Create a Stargate relay for a mail domain hosted in Microsoft Office 365¶
For the relay, we need a VM or a server with a real static IP address.
In this example we will use a VM with IP address 128.140.117.200 and hostname mail.vrgnservices.eu to relay mail for domain vrgnservices.eu.
Set up DNS records¶
See the DNS Setup Guide for complete instructions on all required records (A, MX, SPF, PTR, DMARC, DKIM).
Quick example for domain vrgnservices.eu with Stargate IP 128.140.117.200:
- A record:
mail.vrgnservices.eu→128.140.117.200 - MX record:
MX @ 15 mail.vrgnservices.eu.(higher priority than the existing Exchange MX at 20) - SPF record:
v=spf1 ip4:128.140.117.200 include:spf.protection.outlook.com -all
Verify:
# host -t mx vrgnservices.eu
vrgnservices.eu mail is handled by 20 vrgnservices-eu.mail.protection.outlook.com.
vrgnservices.eu mail is handled by 15 mail.vrgnservices.eu.
# host -t txt vrgnservices.eu|grep v=spf1
vrgnservices.eu descriptive text "v=spf1 ip4:128.140.117.200 include:spf.protection.outlook.com -all"
Install the Stargate docker compose containers¶
Requirements¶
- 2 CPU cores (minimum)
- 4 GB RAM (minimum)
- 20 GB storage (minimum)
- Root access: Must be run as root or with
sudo - Supported distributions:
- RHEL 8, 9 and 10 compatible distributions such as Alma Linux, Rocky Linux, CentOS Stream
- Ubuntu 22 and 24
- Debian 11, 12 and 13
- Real IPv4 address
- Valid DNS records: Your domain must have:
- MX records pointing to your mail servers
- SPF record defining allowed sending networks
The script installs all components and starts them. Mail domains and the Stalwart hostname are then configured at runtime via the dashboard's /mail page (the mtaconf daemon extracts the necessary mail relay settings from DNS based on those domains).
Set up Exchange¶
We need to configure connectors and a transport rule in Exchange to relay all outgoing mail to the Stargate relay and allow incoming mail from it.
Navigate to https://admin.exchange.microsoft.com/#/connectors
Outgoing connector¶
Create an outgoing mail connector, click "Add":
Select "Connection from": "Office 365" "Connection to": "your organization's email server", click "Next".
Name it something like "From Office 365 to Stargate relay server" and check "Retain Internal Exchange email headers", click "Next".
Select "Only when I have a transport rule set up that redirects messages to this connector", click "Next".
Enter the IP address of the Stargate relay server, click "+", click "Next".
Select "Any digital certificate, including self-signed certificates", click "Next".
Enter a valid email address for your domain, click "+", click "Validate", click "Next".
Click "Create connector".
Click "Add another connector".
Incoming connector¶
Create an incoming mail connector, choose "Connection from": "Your organization's email server", click "Next".
Name it something like "Receive mail from Stargate relay server" and check "Retain internal Exchange email headers", click "Next.
Select "By verifying that the IP address of the sending server matches one of the following IP addresses, type the IP address of the Stargate server, click "+", click "Next".
Click "Create connector".
Click "Done".
This is how it looks when done:
Transport Rule¶
Create the transport rule. Navigate to https://admin.exchange.microsoft.com/#/transportrules
Click "+Add a rule" → "Create a new rule".
Name it something like "Relay all mail to Stargate except mail coming from it", choose "Apply rule if" "The recipient:" "is external/internal" "Outside the organization", click "Save".
Choose "Do the following" "Redirect message to the following connector" "From Office 365 to Stargate relay server", click "Save".
Choose "Except if The sender IP address is in any of these ranges" enter the IP address of the Stargate server, click "Add", check the IP address and click "Save".
This is needed to prevent mail loops, as this rule also applies to other domains hosted in Office 365.
Now it should look like this, click "Next":
Click "Next".
Click "Finish".
Click "Done".
Click on the rule and set the "Enable or disable rule" to "Enabled"
DNS Setup for Stargate¶
This guide covers all DNS records required for a working Stargate deployment. Configure these records before installing Stargate or immediately after, depending on the record type.
Throughout this guide:
<STARGATE_IP>- your Stargate server's public static IP address (SERVER_STATIC_IPincustomer-config.sh)<MAIL_HOSTNAME>- the FQDN of the Stargate relay (e.g.mail.example.ch; configured via the dashboard's/mailpage)<YOUR_DOMAIN>- your mail domain (e.g.example.ch; configured via the dashboard's/mailpage)
Record Summary¶
| Record | Name | Value | Required | When |
|---|---|---|---|---|
| A | <MAIL_HOSTNAME> |
<STARGATE_IP> |
Yes | Before install |
| MX | <YOUR_DOMAIN> |
<MAIL_HOSTNAME> (priority 15) |
Yes | Before install |
| SPF | <YOUR_DOMAIN> |
ip4:<STARGATE_IP> added to TXT |
Yes | Before install |
| PTR | <STARGATE_IP> |
<MAIL_HOSTNAME> |
Recommended | Before install |
| DMARC | _dmarc.<YOUR_DOMAIN> |
v=DMARC1; p=none; ... |
Recommended | After install |
| DKIM | selector._domainkey.<YOUR_DOMAIN> |
From M365/provider | Recommended | After install |
For multi-domain deployments, repeat the MX, SPF, DMARC, and DKIM records for each domain listed in MAIL_DOMAINS.
Required Records¶
A Record¶
Create an A record pointing the Stargate mail hostname to the server's public IP:
Example:
If the Stargate has an IPv6 address, add an AAAA record as well:
Why: External mail servers connect to this hostname to deliver mail. Without the A record, the MX record below is unresolvable.
MX Records¶
Add an MX record for the Stargate with a higher priority (lower number) than the existing mail server. This ensures inbound mail reaches the Stargate first for S/MIME processing before being forwarded to Exchange or your mail platform.
Keep the existing Exchange / mail server MX record at a lower priority (higher number):
Example (complete MX set):
Info
The lower MX number means higher priority. Stargate at priority 15 receives mail before Exchange Online at priority 20.
Why: The Stargate intercepts inbound mail, processes S/MIME, then forwards to the next MX (Exchange). The second MX record is also used by Stalwart to know where to relay processed mail.
Important: If the Stargate is the only MX record for a domain, Stalwart will filter out its own hostname and have no delivery target. Always keep a second MX pointing to your actual mail server.
SPF Record¶
Add the Stargate server IP and the HIN sealer IP to your domain's SPF record so outbound mail relayed through it passes SPF checks at the recipient's end.
If you use M365 / Exchange Online:
<YOUR_DOMAIN>. TXT "v=spf1 ip4:<STARGATE_IP> ip4:<HIN_SEALER_IP> include:spf.protection.outlook.com -all"
If you do not use M365 / Google Workspace:
Example:
example.ch. TXT "v=spf1 ip4:128.140.117.200 ip4:193.247.208.66 include:spf.protection.outlook.com -all"
Why the HIN sealer IP is required
When the Stargate produces a SEAL'd (encrypted) message for a non-HIN recipient, the final outbound hop to the recipient is the HIN sealer, not your Stargate or M365. Without the sealer IP in your SPF record, every SEAL'd outbound message will fail SPF at the recipient and - because there is no DKIM signature on the SEAL'd payload - DMARC will fail too. Strict-DMARC recipients (Gmail, Outlook with p=reject enforcement, Proofpoint) will reject or junk the message.
Sealer IPs to add in SPF:
| Environment | Sealer host | IP to add to SPF |
|---|---|---|
| HIN Test (alpha/beta) | mx3.hintest.ch |
193.247.208.66 |
| HIN Production | TBD - request canonical list from HIN before go-live | TBD |
If HIN publishes more than one sealer host (e.g. mx1, mx2, mx3), include all their IPs. Resolve them with dig +short mx hintest.ch followed by dig +short A <each-mx>. Until you have the full list, leave the SPF policy at ~all (softfail) instead of -all (hardfail) so that legitimate SEAL mail through any unlisted sealer IP is not outright rejected.
SPF lookup limit
The total include: chain in an SPF record must stay under 10 DNS lookups. Adding ip4: entries does not count toward this limit. Check your count with MXToolbox SPF lookup.
How the Stargate uses SPF: The mtaconf daemon resolves each domain's SPF record to auto-populate the list of IPs allowed to relay through the Stargate without authentication. This is how Microsoft 365 outbound IPs get whitelisted automatically - they appear in the include:spf.protection.outlook.com chain.
Recommended Records¶
PTR (Reverse DNS)¶
Configure the reverse DNS (PTR) record for the Stargate IP to match <MAIL_HOSTNAME>:
This is configured at your hosting provider (Hetzner, Azure, AWS, etc.), not in your domain registrar's DNS panel. Most providers have a "Reverse DNS" or "rDNS" setting in the server/IP management page.
Why: Many receiving mail servers (including Gmail and Outlook) check that the connecting IP's PTR record resolves to a hostname, and that hostname resolves back to the same IP (forward-confirmed reverse DNS / FCrDNS). A missing or mismatched PTR is a strong spam signal and can cause delivery failures.
DMARC Record¶
Publish a DMARC policy for each sending domain. Start with p=none (monitoring only), then tighten after confirming alignment:
Example:
Once DMARC aggregate reports confirm that SPF and/or DKIM pass consistently, tighten the policy:
p=none- monitoring only (start here)p=quarantine- suspicious mail goes to spamp=reject- unauthorized mail is rejected
Why: DMARC ties SPF and DKIM together and tells recipients what to do with mail that fails both. Even p=none is enough to clear Outlook's "we can't verify this sender" banner, as long as SPF passes.
Check your DMARC record: MXToolbox DMARC lookup
DKIM Records¶
If your domain is an accepted domain in M365 or Google Workspace, enable DKIM signing in the admin centre and publish the CNAME records as instructed:
M365 example:
selector1._domainkey.<YOUR_DOMAIN>. CNAME selector1-<YOUR_DOMAIN_DASHED>._domainkey.<TENANT>.onmicrosoft.com.
selector2._domainkey.<YOUR_DOMAIN>. CNAME selector2-<YOUR_DOMAIN_DASHED>._domainkey.<TENANT>.onmicrosoft.com.
Note
Publishing the CNAME records alone is not enough - DKIM signing must also be enabled in the M365 admin centre (Defender portal > Email authentication > DKIM).
Why: DKIM proves the message body was not tampered with in transit. When combined with SPF and DMARC, it provides the strongest sender authentication.
Multi-Domain Setup¶
For deployments handling multiple mail domains (configured via the dashboard's /mail page), each domain needs its own set of DNS records.
Per-Domain Records¶
For each configured domain:
| Record | Required |
|---|---|
MX pointing to <MAIL_HOSTNAME> |
Yes |
SPF including ip4:<STARGATE_IP> |
Yes |
DMARC (_dmarc.<domain>) |
Recommended |
| DKIM (from your mail provider) | Recommended |
The A record and PTR record are shared (they point to the Stargate server, not to individual domains).
Per-Domain Mail Routing¶
Each domain's MX records tell the Stargate where to deliver processed mail. If different domains use different Exchange servers:
domain1.ch MX 15 mail.domain1.ch.
domain1.ch MX 20 exchange1.domain1.ch.
domain2.ch MX 15 mail.domain2.ch.
domain2.ch MX 20 exchange2.domain2.ch.
Alternatively, configure explicit per-domain relay targets via the dashboard's /mail page (relay host field per domain) to override MX-based routing.
Verification¶
After configuring all records, verify them:
# A record
host <MAIL_HOSTNAME>
# Expected: <MAIL_HOSTNAME> has address <STARGATE_IP>
# MX records
host -t mx <YOUR_DOMAIN>
# Expected: Both Stargate and Exchange MX records listed
# SPF record
host -t txt <YOUR_DOMAIN> | grep v=spf1
# Expected: SPF record includes ip4:<STARGATE_IP>
# PTR (reverse DNS)
host <STARGATE_IP>
# Expected: <STARGATE_IP> → <MAIL_HOSTNAME>
# Forward-confirmed reverse DNS (FCrDNS)
host $(host <STARGATE_IP> | awk '{print $NF}' | sed 's/\.$//')
# Expected: resolves back to <STARGATE_IP>
# DMARC
host -t txt _dmarc.<YOUR_DOMAIN>
# Expected: v=DMARC1; p=...
# DKIM (M365)
host -t cname selector1._domainkey.<YOUR_DOMAIN>
# Expected: CNAME to your tenant's onmicrosoft.com
Example output:
$ host mail.example.ch
mail.example.ch has address 128.140.117.200
$ host -t mx example.ch
example.ch mail is handled by 15 mail.example.ch.
example.ch mail is handled by 20 example-ch.mail.protection.outlook.com.
$ host -t txt example.ch | grep v=spf1
example.ch descriptive text "v=spf1 ip4:128.140.117.200 include:spf.protection.outlook.com -all"
$ host 128.140.117.200
200.117.140.128.in-addr.arpa domain name pointer mail.example.ch.
$ host -t txt _dmarc.example.ch
_dmarc.example.ch descriptive text "v=DMARC1; p=none; rua=mailto:postmaster@example.ch"
Online tools:
- MXToolbox MX Lookup
- MXToolbox SPF Check (includes lookup count)
- MXToolbox DMARC Check
- Mail-Tester (send a test mail to get a deliverability score)
Troubleshooting¶
"Client host rejected: Access denied" (554 5.7.1)¶
Stalwart is rejecting the sending server because its IP is not in the allowed relay list. This usually means:
- The SPF record for your domain does not include the sending server's IP range
- The mail configuration has not been reloaded since the SPF record was updated
Reload the mail configuration via the dashboard's /mail page (submit the config again), or restart the container: docker compose restart stalwart
Mail flagged as spam / "can't verify sender"¶
- SPF is missing or does not include the Stargate IP - add
ip4:<STARGATE_IP>to your SPF record - DMARC is not published - add at least
v=DMARC1; p=none - PTR record is missing or mismatched - configure reverse DNS at your hosting provider
- DKIM is not enabled in your M365/provider tenant
MX lookup returns only the Stargate¶
If the Stargate is the only MX for a domain, Stalwart filters out its own hostname and has no relay target. Add a second MX record pointing to your mail server:
example.ch. MX 15 mail.example.ch. ← Stargate (inbound)
example.ch. MX 20 example-ch.mail.protection.outlook.com. ← Exchange (relay target)
SPF lookup count exceeded (> 10)¶
Each include: in the SPF record triggers additional DNS lookups. The total chain must stay under 10. Solutions:
- Use
ip4:/ip6:entries instead ofinclude:where possible (they do not count) - Flatten nested includes using a tool like SPF Flattener
- Remove unused
include:entries from old providers
Port 25 blocked by hosting provider¶
Some cloud providers (Azure, certain Hetzner plans) block outbound port 25 by default. Check with your provider and request an exception. This affects both inbound delivery (external servers connecting to your Stargate) and outbound relay (Stargate delivering to MX targets).
Server install
Container
Stargate Docker deployment¶
Prerequisites¶
Server Requirements:
Please refer to Recommended Requirements
- Docker will be installed automatically if missing
- Ensure there is an internet connection on the machine where you are installing Stargate services
- Ensure traffic is properly configured to reach the Stargate instance
Step 1: Configure Customer Settings¶
Tip
You can clone our repository with all data and sample configs inside with a command:
If you do not have git installed, you can always get an archive with all files inside. Download it via the following link. Download as ZIP
The installer creates customer-config.sh automatically from the bundled template on first run, so a fresh install needs no manual configuration. If you prefer to create it yourself, copy the template:
You do not need to edit it - every value is either auto-detected or configured later via the dashboard:
| Setting | How it is set |
|---|---|
SERVER_STATIC_IP |
Auto-detected from the server's primary network interface. |
CUSTOMER_NAME |
Defaults to the system hostname. |
DEPLOYMENT_NAME |
Derived from CUSTOMER_NAME (used in log labels and the Alloy hostname). |
Passwords & keys (POSTGRES_PASSWORD, S3_SECRET_KEY, VAULT_TOKEN, WG_PRIVATE_KEY) |
Generated securely on first run and saved back to customer-config.sh. |
Mail domains, the mail hostname, S/MIME certificates, and WireGuard peers are all configured at runtime via the dashboard after the stack is up - they are not part of customer-config.sh.
Behind NAT or a floating IP?
Auto-detection uses the IP of the server's primary interface. If your server is reached on a different public or floating IP (common with NAT), set SERVER_STATIC_IP to that public IP in customer-config.sh before installing, so the dashboard and Keycloak login URLs point at the reachable address. Otherwise leave it empty.
Auto-derived settings — leave empty unless you need to override:
| Setting | Derived from | Default |
|---|---|---|
MXENGINE_PUBLIC_ADDRESS |
SERVER_STATIC_IP |
http://<SERVER_STATIC_IP>:8084 |
S/MIME certificate settings:
| Setting | Description | Default |
|---|---|---|
CERT_CA_IRISAGENT_DOMAIN |
CA domain for certificate issuance via WireGuard tunnel | hintest.ch |
Note
WireGuard peer setup is performed at runtime via the dashboard (/installation page). Peer details are configured per deployment after the stack is up - they are not part of customer-config.sh.
WireGuard local settings (typically left at defaults):
| Setting | Default | Description |
|---|---|---|
WG_PRIVATE_KEY |
(auto-generated) | Generated by IRISAgent on first run, then saved to customer-config.sh |
WG_LOCAL_IP |
SERVER_STATIC_IP |
Auto-derived. Only override if you need a different tunnel address. |
WG_INTERFACE_PORT |
19818 |
WireGuard tunnel port (both TCP and UDP are exposed) |
WG_TRANSPORT_MODE |
tcp |
Transport protocol: tcp (default, works through most firewalls) or udp |
Optional settings (have sensible defaults):
| Setting | Default | Description |
|---|---|---|
POSTGRES_PASSWORD |
(auto-generated) | Auto-generated 24-character random password if empty |
S3_SECRET_KEY |
(auto-generated) | S3 secret key for object storage |
OUTBOUND_SEALER_MX_DOMAIN |
hintest.ch |
Sealer MX domain for outbound seal delivery |
POLICY_SYNC_REPO_URL |
GitHub HIN Stargate policies | Git repo URL for OPA/Rego policy sync |
LOKI_URL |
(unset) | Loki endpoint for centralized log shipping (e.g. https://loki.example.com) |
Auto-generated (do not set manually):
VAULT_TOKEN— Generated by Vault during first initialization, saved tocustomer-config.shWG_PRIVATE_KEY— Generated by IRISAgent on first run, saved tocustomer-config.sh
Step 2: Deploy to a Server¶
Tip
You can clone our repository with all data and sample configs inside with a command:
git clone https://github.com/Health-Info-Net-AG/Stargate-deployment.git && \
cd Stargate-deployment-main
If you do not have git installed, you can always get an archive with all files inside and extract it:
Manually copy files to the server
SSH to server
Create customer config from template and fill in required settings (see Step 1)
cp customer-config-prod.example.sh customer-config.sh
nano customer-config.sh # Fill in required settings (see Step 1)
Run installation
Step 3: What Install Does¶
The install script (install.sh) performs the following steps:
- Check dependencies — Detects Docker, Docker Compose, and
jq. If missing, installs them automatically (supports Ubuntu/Debian, RHEL/AlmaLinux/Rocky). - Load and validate
customer-config.sh— Checks required fields (SERVER_STATIC_IP,CUSTOMER_NAME,DEPLOYMENT_NAME). Auto-derives optional fields (MXEngine URL, etc.). - Generate
.envfrom customer config — Auto-generates passwords if not set. - Start all services via Docker Compose (infrastructure + applications).
- Initialize Vault — The
vault-initcontainer initializes, unseals, and creates KV-v2 secret mounts. Optionally writes the WireGuard private key to Vault. - Save Vault keys to
secrets/vault-keys.jsonand update.envwith the root token. The token is also saved tocustomer-config.shfor persistence across VM recreations. - Restart application services to pick up the Vault token.
- Save WireGuard private key to
customer-config.sh— extracted from Vault after IRISAgent generates it. - Set up daily backup cron job (runs at 2:00 AM).
After install completes, the stack is running but no mail domains, S/MIME certificate, or WireGuard peer are set up yet. Continue with Step 4: Onboard via the dashboard.
Step 4: Onboard via the dashboard¶
After installation, complete onboarding through the dashboard at https://<SERVER_STATIC_IP>. The dashboard walks you through three pages in order:
/installation — WireGuard peer setup¶
Performs the nonce/HIN handshake to establish a WireGuard peer connection, and saves the resulting WireGuard configuration to the IRISAgent service.
/onboarding — S/MIME certificate¶
Generates the S/MIME signing key and CSR via the smimekeys service and submits the CSR to the CA over the now-established WireGuard tunnel. (This replaces the previous script-based certificate flow.)
/mail — Mail domains and relay configuration¶
Submits hostname and the list of relay domains to the mtaconf service over its REST API. The daemon applies the configuration to Stalwart without restarting the container.
Adding or changing domains later
Re-open the /mail page in the dashboard, edit the domain list, and submit. The daemon applies the change at runtime - no script invocation, no .env edit, no service restart needed.
Step 5: WireGuard Peer Registration¶
The S/MIME CSR submission on /onboarding will fail if your Stargate instance is not yet registered as a WireGuard peer on the HIN CA side. This is the most common issue during initial setup.
The dashboard's /installation page handles the WireGuard peer registration automatically via the nonce/HIN handshake. If the automatic registration fails, manual registration can be done by providing the following values to HIN:
- WireGuard public key — extract from irisagent logs:
DEPLOYMENT_NAME— from yourcustomer-config.shSERVER_STATIC_IP— the public IP of your Stargate serverWG_INTERFACE_PORT— only if you changed it from the default19818
After peer registration is confirmed:
Re-run the /onboarding page in the dashboard to regenerate the CSR and submit it through the now-up tunnel.
To verify the tunnel before requesting the certificate:
Restart just irisagent
Check for successful WireGuard handshake
Tip
Check your firewall: Port 19818/TCP must be open both directions inbound and outbound on the Stargate server.
Step 6: Post-Onboarding Recommendations¶
Once the certificate is issued and mail is flowing, two configuration items are strongly recommended for any production deployment. Skipping them does not break encryption, but it will degrade your sender reputation, cause "we can't verify the sender" warnings in Outlook/Gmail, and can eventually lead to outbound mail being blocklisted.
Step 6.1 SPF / DKIM / DMARC for sender domains¶
The Stargate sends mail from its own public IP on behalf of your users. Without proper DNS authentication records, recipients will see "we can't verify this sender" warnings and may reject the mail.
For complete instructions on configuring SPF, DKIM, DMARC, and PTR records, see the DNS Setup Guide.
At minimum, for each domain you route through the Stargate:
- SPF: add
ip4:<STARGATE_IP>to the domain's TXT record - DMARC: publish
v=DMARC1; p=noneat_dmarc.<YOUR_DOMAIN> - PTR: set reverse DNS for the Stargate IP to match
MAIL_HOSTNAME
Step 6.2 Relay outbound mail back through your mail platform (recommended for M365 / Exchange Online)¶
By default, after the Stargate signs/encrypts an outbound mail it delivers directly to the recipient's MX. This works, but the connecting IP is your Stargate's IP - and unless that IP has years of warm reputation, it can end up on third-party blocklists (e.g. Barracuda, Abusix), causing intermittent delivery failures.
The recommended pattern is to send the signed mail back through your M365 / Exchange tenant so that the final hop to the internet is Microsoft's well-reputed infrastructure. The Stargate still signs and policy-checks every message; only the last hop changes. This mirrors the original HIN MGW "Send to MX" connector pattern.
Stargate side — per-domain relay¶
Configure per-domain relay through the dashboard's /mail page. Each domain can be mapped to its own M365 / Exchange inbound endpoint; the dashboard sends the mapping to mtaconf's REST API and Stalwart is reconfigured at runtime.
After mxengine signs the mail, Stalwart will hand it back to your tenant on port 25 with TLS instead of delivering directly to the recipient's MX. See Exchange-integration.md for the full per-domain syntax.
M365 / Exchange Online side¶
You essentially recreate the same connector + transport rule set as the old HIN MGW (the original HIN MGW O365 manual is the reference - the same five rules apply). The minimum is:
- Inbound connector - accept mail from the Stargate, identified by TLS certificate (the cert subject must match a domain accepted in your tenant). A self-signed cert on the Stargate will be rejected by this connector - use a valid CA-issued cert (Let's Encrypt is fine).
- Outbound connector "Send to MX" - delivers to the recipient's MX, activated only by transport rule.
- Transport rule
set_header- tags outbound mail with a header likeoutgoing: outgoing_<domain>before it leaves O365 the first time, so the return trip can recognize it. - Transport rule
outgoing_to_mx- matches theoutgoing_<domain>header on mail coming back from the Stargate and routes it via the "Send to MX" connector. - Transport rule
mgw_bypass_antispam- bypasses spam filtering on mail coming back from the Stargate.
mxengine does not strip arbitrary headers, so the outgoing_<domain> tag set by set_header survives the round-trip and triggers outgoing_to_mx correctly.
Why this pattern matters
With the relay-back configuration, the public sender to the internet is Microsoft. Combined with correct SPF/DKIM/DMARC (section 6.1), recipients see a Microsoft IP with spf=pass and dkim=pass aligned to your domain - which is the cleanest reputation profile you can give them.
See Exchange-integration.md for full step-by-step instructions including screenshots.
Subsequent Starts (after reboot)¶
The installer enables a stargate systemd unit, so the stack starts
automatically on boot. To start it manually:
This runs start.sh, which:
- Starts infrastructure services
- Unseals Vault using stored keys
- Starts application services
(./scripts/start.sh still works directly if you prefer.)
Stop Services¶
(or ./scripts/stop.sh directly)
This stops containers but preserves all data.
Data Persistence¶
All data is stored in Docker volumes and persists across restarts.
| Service | Volume | Data |
|---|---|---|
| PostgreSQL | postgres_data |
All databases (smimekeys, policy, irisagent, mxengine) |
| Vault | vault_data |
Encryption keys, secrets, S/MIME keys |
| SeaweedFS | seaweedfs_data |
Object storage (messages, attachments) |
| Stalwart | stalwart_data |
Mail server state |
Safe Operations (data preserved)¶
Stop and start:
Or using the scripts directly:
Do not use docker compose commands directly
Always use systemctl or the provided scripts (start.sh / stop.sh) to manage the deployment. Running docker compose up, docker compose down, or docker compose restart directly will not unseal Vault, leaving dependent services unable to start. The start.sh script handles the Vault unseal procedure automatically.
Vault Sealing Behavior¶
Vault becomes sealed when its container restarts. This is a security feature.
The start.sh script (and the systemd service) automatically unseal Vault using the keys stored in secrets/vault-keys.json. This is why you must always use the provided scripts or systemd service to manage the stack.
Destructive Operations (data deleted)¶
Warning
These commands DELETE ALL DATA - use with caution!
You can only restore data if you perform backup operations before and save the backup in a safe place.
Danger
Delete everything (volumes, secrets, config)
Or manually remove volumes. The -v flag removes volumes
Scripts Reference¶
| Script | Purpose |
|---|---|
install.sh |
First-time installation (Docker, Vault). Domain/cert/peer setup happens in the dashboard afterwards. |
update.sh |
Update service images (preserves Vault token, recreates containers) |
start.sh |
Start services and unseal Vault |
stop.sh |
Stop containers (data preserved) |
backup.sh |
Full backup (database, Vault keys, config, certificates) |
restore.sh |
Restore from backup archive (works on fresh machine) |
purge.sh |
|
health-check.sh |
Comprehensive health check of all services (exit 0 = healthy, 1 = failures) |
init-vault.sh |
Vault initialization (used by vault-init container, not called directly) |
init-keycloak.sh |
Keycloak admin password setup (used by keycloak-init container, not called directly) |
gather-app-versions.sh |
Collects app versions from /liveness endpoints for node-exporter (runs in version-collector container) |
Configuration Files¶
| File | Purpose |
|---|---|
customer-config-prod.example.sh |
Template for customer settings (copy to customer-config.sh) |
customer-config.sh |
Customer-specific settings (created from template, fill in before install) |
.env |
Generated environment file (created by install.sh) |
secrets/vault-keys.json |
Vault unseal keys and root token (back up securely!) |
secrets/signing-key.csr |
Generated CSR for S/MIME certificate |
Support¶
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
Stargate Docker advanced configuration¶
Backups¶
Automatic Backups¶
- Daily backups run at 2:00 AM via cron (set up during install)
- Backups stored in
./backups/as timestamped.tar.gzfiles - Old backups (>7 days) are automatically cleaned up
What's Included in Backups¶
- Full PostgreSQL dump (all databases with users and permissions)
- Individual database dumps (for partial restore if needed)
- Vault keys (
vault-keys.jsonfor unsealing) - Customer configuration (
customer-config.shwith WireGuard key) - S/MIME CSR and certificates (any
.crt,.pem,.cerfiles) - Backup manifest (
manifest.jsonwith metadata)
Manual Backup¶
Creates a compressed archive in ./backups/YYYYMMDD_HHMMSS.tar.gz.
Restore from Backup¶
To restore on a new machine or after a purge. Copy the backup archive to the new machine and execute:
The restore script will:
- Stop any running services
- Extract and validate the backup
- Install Docker if needed
- Restore customer configuration
- Start infrastructure services (PostgreSQL, Vault, MinIO)
- Restore the database
- Unseal Vault with backed-up keys
- Start application services
Partial Restore (single database)¶
If you only need to restore one database:
Extract backup¶
Restore a specific database¶
cat /tmp/20260130_143022/database/mxengine.sql | docker exec -i stargate-postgres psql -U postgres -d mxengine
Updating Stargate¶
Update Deployment Scripts and Configuration¶
The Stargate deployment repository receives updates to scripts (install.sh, start.sh, health-check.sh, restore.sh, etc.), configuration templates, and documentation. To apply these updates:
1. Create a backup before updating¶
2. Fetch and apply the latest changes¶
The repository is the single source of truth for tracked files, so update by resetting to the latest revision. This replaces tracked files (scripts, docker-compose.yml, config templates) with the repository's versions:
3. Restart services to pick up any script or config changes¶
Note
Your customer-config.sh, .env, and secrets/ directory are in .gitignore, so this does not touch them - your configuration and credentials are preserved. Always put customisation in customer-config.sh, never by editing tracked files such as docker-compose.yml: a hard reset - and the automatic updates triggered from the dashboard - will revert any tracked-file edits. This is intentional; keeping every deployment identical to the repository is what lets updates apply reliably and without manual conflict resolution.
If the update includes changes to the config template, compare it with your existing config to see if new variables were added:
Update Service Images¶
Application versions are managed exclusively through the dashboard. Each release is a versioned manifest that pins a known-good, tested combination of all service versions together; the dashboard's update page lists the available releases, and applying one pulls the matching images and recreates the affected services for you.
To update:
- Open the dashboard and go to the update page.
- Select the target release.
- Confirm - the dashboard applies the release manifest and recreates the changed services.
Do not manually change versions
Do not edit individual *_VERSION values in customer-config.sh or .env to update applications. Versions are released and tested together as a set - hand-picking one produces an untested combination, and the change would be reverted by the next dashboard update anyway. Always update from the dashboard.
Cleanup Old Images¶
After updates, remove unused images to free disk space:
Rollback¶
To roll back, select an earlier release on the dashboard's update page and apply it - the same mechanism runs in reverse, pinning the previous tested set. Do not roll back by editing versions by hand.
Configuration¶
The .env file is generated by install.sh from customer-config.sh. Domain, certificate, and WireGuard settings are managed at runtime by the dashboard (/installation, /onboarding, /mail) — they are not held in .env. To customize the install-time settings, edit customer-config.sh and re-run install.sh.
Key sections in the generated .env:
## PostgreSQL (auto-generated if empty in customer-config.sh)
POSTGRES_USER=postgres
POSTGRES_PASSWORD=<auto-generated>
## Vault (auto-populated after initialization)
VAULT_TOKEN=<auto-generated>
## S3 Object Storage (SeaweedFS)
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=<auto-generated>
## Application Versions
SMIMEKEYS_VERSION=v0.0.5
POLICY_VERSION=v0.0.5
IRISAGENT_VERSION=v0.0.6-branch
MXENGINE_VERSION=v0.0.35
MTACONF_VERSION=dev
## Mail Outbound Path
MXENGINE_PUBLIC_ADDRESS=http://203.0.113.50:8084
OUTBOUND_SEALER_MX_DOMAIN=hintest.ch
## WireGuard
WG_LOCAL_IP=203.0.113.50
WG_INTERFACE_PORT=19818
WG_TRANSPORT_MODE=tcp
Warning
Do not edit .env directly. Changes will be overwritten on re-run of install.sh. For runtime configuration (domains, hostname, peers, S/MIME), use the dashboard.
Service URLs¶
| Service | URL/Port |
|---|---|
| Dashboard | https://localhost |
| smimekeys-client | http://localhost:8081 |
| policy | http://localhost:8082 |
| irisagent | http://localhost:8083 |
| mxengine HTTP | http://localhost:8084 |
| Stalwart SMTP | localhost:25 |
| APISIX Gateway | http://localhost:9080 |
| Keycloak | https://localhost:8180 |
Health Checks¶
All services expose a /liveness endpoint:
curl http://localhost:8081/liveness # smimekeys-client
curl http://localhost:8082/liveness # policy
curl http://localhost:8083/liveness # irisagent
curl http://localhost:8084/liveness # mxengine
Monitoring¶
Prometheus Metrics¶
All application services expose Prometheus metrics on port 2112 (internally), mapped to different host ports:
| Service | Metrics Port | Metrics URL |
|---|---|---|
| smimekeys-client | 2113 |
http://localhost:2113/metrics |
| irisagent | 2114 |
http://localhost:2114/metrics |
| policy | 2115 |
http://localhost:2115/metrics |
| mxengine | 2116 |
http://localhost:2116/metrics |
| node-exporter | 9100 |
http://localhost:9100/metrics |
Prometheus Scrape Config Example¶
scrape_configs:
- job_name: 'stargate-smimekeys'
static_configs:
- targets: ['<host>:2113']
- job_name: 'stargate-irisagent'
static_configs:
- targets: ['<host>:2114']
- job_name: 'stargate-policy'
static_configs:
- targets: ['<host>:2115']
- job_name: 'stargate-mxengine'
static_configs:
- targets: ['<host>:2116']
- job_name: 'stargate-node'
static_configs:
- targets: ['<host>:9100']
Quick Metrics Check¶
## Check all metrics endpoints
curl -s http://localhost:2113/metrics | head -20 # smimekeys-client
curl -s http://localhost:2114/metrics | head -20 # irisagent
curl -s http://localhost:2115/metrics | head -20 # policy
curl -s http://localhost:2116/metrics | head -20 # mxengine
curl -s http://localhost:9100/metrics | head -20 # node-exporter
Log Collection (Alloy → Loki)¶
Alloy collects logs from application containers and ships them to Loki.
Containers monitored:
- stargate-apisix
- stargate-keycloak
- stargate-dashboard
- stargate-smimekeys-client
- stargate-policy
- stargate-policy-sync
- stargate-irisagent
- stargate-mxengine
Configuration in .env:
## Loki push URL
LOKI_URL=https://loki.example.com
## Hostname label for logs (auto-set to DEPLOYMENT_NAME)
ALLOY_HOSTNAME=stargate-acme
Labels added to logs:
environment=<DEPLOYMENT_NAME>- Identifies the deploymenthost=<ALLOY_HOSTNAME>- Identifies the host (same as deployment name)container=<container-name>- Container nameservice=<service-name>- Service name (e.g., smimekeys-client, policy)level=<log-level>- Extracted from JSON logs if available
Query logs in Grafana:
{environment="stargate-acme"} |= "error"
{environment="stargate-acme", service="mxengine"}
{environment="stargate-acme", level="error"}
Verify Alloy is working:
Note: The VM's public IP must be whitelisted in Loki's ingress configuration.
Stalwart MTA + mtaconf¶
Stargate uses Stalwart as the mail transfer agent and mtaconf as the configuration daemon. The dashboard sends domain and relay configuration to mtaconf's REST API, which pushes it to Stalwart via the management CLI.
Mail Flow Architecture¶
External Mail Server
│
▼ (port 25)
┌─────────────────────────────────────────────────────┐
│ stalwart (stargate-stalwart) │
│ │
│ Port 25 (smtp listener) │
│ │ │
│ ▼ │
│ content_filter → smtp:[mxengine]:1587 │
│ │ │
└────┼────────────────────────────────────────────────┘
│
▼ (port 1587)
┌─────────────────────────────────────────────────────┐
│ MXEngine (stargate-mxengine) │
│ │
│ Port 1587 (SMTP input) │
│ │ │
│ ▼ │
│ Sign/encrypt/process mail │
│ │ │
│ ▼ │
│ Deliver back to stalwart for relay │
│ │ │
└────┼────────────────────────────────────────────────┘
│
▼ (port 10026)
┌─────────────────────────────────────────────────────┐
│ stalwart (stargate-stalwart) │
│ │
│ Port 10026 (reinject listener) │
│ │ │
│ ▼ │
│ transport → relay to destination MX │
│ │ │
└────┼────────────────────────────────────────────────┘
│
▼ (port 25)
Destination Mail Server (via MX lookup)
Antivirus scanning: Inbound mail is scanned by ClamAV (stargate-clamav), wired into Stalwart as a milter at the SMTP DATA stage on both the public (:25) and reinject (:10026) listeners. Infected mail is rejected at the SMTP level; if ClamAV is unreachable the message is deferred rather than delivered unscanned (fail-closed). ClamAV's signature database lives in the clamav_data volume and is kept current by freshclam in the background.
Seal callback flow (inbound): When a remote sealer needs to deliver a sealed message, it calls MXENGINE_PUBLIC_ADDRESS (default: http://<SERVER_STATIC_IP>:8084). This is why port 8084 must be open for inbound traffic. The http:// protocol is correct - TLS is not required because the seal payload is already encrypted.
Mail Relay Configuration¶
All mail configuration that varies per deployment (mail domains, hostname, relay host, per-domain relay maps, allowed networks) is set through the dashboard's /mail page at runtime. The dashboard POSTs the configuration to mtaconf's REST API, which applies it to Stalwart without restarting the container.
There is no per-domain config in customer-config.sh or .env - operators add or change domains through the UI.
Mail Routing (Migrating from Old MGW)¶
Key difference from the old HIN-MGW
In the old MGW, you had to manually configure a target server per domain. In Stargate, mail routing is decided by DNS MX records by default - Stalwart resolves each domain's MX at delivery time. The dashboard's /mail page lets you override this per-domain (e.g. to relay back through your M365 / Exchange tenant) without touching DNS.
Default - automatic via DNS MX:
For each of your domains, make sure there is an MX record in DNS pointing to the corresponding Exchange (or other mail) server:
domain1.com MX 10 exchange1.domain1.com
domain2.com MX 10 exchange2.domain2.com
domain3.com MX 10 exchange3.domain3.com
This works for any number of domains - each domain can point to a different mail server, and Stalwart will route accordingly.
If Stargate is the only MX record for a domain, Stalwart will filter it out and have no delivery target. Add a second MX record pointing to your mail server with a higher priority (= lower number) so Stalwart uses it as the delivery target:
example.com MX 10 exchange.example.com ← delivery target (mail server)
example.com MX 20 stargate.example.com ← inbound gateway (Stargate)
Alternative - explicit per-domain relay (sender-based):
For relay-back through M365 / Exchange Online, configure per-domain relay targets through the dashboard's /mail page. Mail from senders not in the map falls back to MX lookup.
Ports¶
| Port | Purpose |
|---|---|
25 |
Main SMTP listener (external connections) |
10026 |
Reinjection port (mxengine → stalwart, internal only) |
1587 |
MXEngine SMTP input (stalwart → mxengine, internal only) |
8080 |
Stalwart management API + mtaconf REST API (internal only) |
Using Exchange?
See Exchange-integration for the full Exchange Online / On-Premises connector and transport rule setup.
Verification¶
Check Stalwart status
Check logs
Test connection to port 25
Test internal port 10026 (from mxengine container)
Updating the mtaconf image¶
Like every service, the mtaconf image version is part of a release and is updated through the dashboard - not by editing its tag by hand. Select the target release on the dashboard's update page to apply it.
Stargate Troubleshooting¶
Mail not being processed by mxengine:
- Check content_filter is configured: verify mtaconf logs show successful push
- Verify mxengine is reachable:
docker exec stargate-stalwart nc -zv mxengine 1587
Mail stuck after mxengine processing:
- Check mxengine outbound config: OUTBOUND_SMTP_HOST=stalwart, OUTBOUND_SMTP_PORT=10026
- Verify port 10026 listener is active in Stalwart
- Check allowed relay networks include Docker network (172.x.x.x/16)
Greylisting errors (450 4.7.1):
- This is normal! The destination server is temporarily rejecting mail
- Stalwart automatically retries after a configurable delay
- Check queue via management API
Microsoft blocking IP (S3140):
- Your server's IP has poor reputation with Microsoft
- Request delisting at: https://sender.office.com
- May take 24-48 hours to take effect
DNS Lookup Failures:
- Use the dashboard's
/mailpage to set an explicit relay host or per-domain relay map (skips MX-based discovery)
Connection Refused on port 25:
- Ensure port 25 is not blocked by the firewall
- Check if another service is using port 25:
ss -tlnp | grep :25
WireGuard (Agent-to-Agent Communication)¶
IRISAgent uses WireGuard to establish secure encrypted tunnels between Stargate instances for delivering sealed messages.
How It Works¶
Each Stargate instance uses its server's real static public IP as the WireGuard tunnel address. This guarantees uniqueness across all deployments without manual coordination.
block
columns 5
block:Stargate["Your Stargate (203.0.113.50)"]:2
columns 1
A
space
A --> B
A["IRISAgent (203.0.113.50:19818)"]
B["Sealed message delivery via WG tunnel"]
end
blockArrowId1<["WG Tunnel (TCP)"]>(x):1
block:mxengine["HIN Test (5.102.144.182)"]:2
columns 1
C
space
C --> D
C["IRISAgent (5.102.144.182:19818)"]
D["Receive sealed message"]
end
WireGuard Configuration¶
WireGuard settings in customer-config.sh:
## ==============================================================================
## Server IP — used as WireGuard tunnel address and MXEngine callback URL
## ==============================================================================
SERVER_STATIC_IP="203.0.113.50" # Your server's real static public IP
## ==============================================================================
## WireGuard local settings (typically left at defaults)
## ==============================================================================
WG_PRIVATE_KEY="" # Auto-generated by IRISAgent, then saved back to config
WG_INTERFACE_PORT="19818" # Default WireGuard port
WG_TRANSPORT_MODE="tcp" # "tcp" (default) or "udp"
Info
WG_LOCAL_IP is auto-derived from SERVER_STATIC_IP. You do not need to set it separately.
Peer Connection Setup¶
WireGuard peer details (public key, endpoint, allowed IPs, etc.) are configured at runtime through the dashboard's /installation page. There is no WG_PEER_* block in customer-config.sh anymore — the peer is set up after the stack is up.
For first-time setup with the HIN Test environment:
- Bring up the stack with
./scripts/install.sh. - Open the dashboard, follow
/installationto start the nonce / HIN handshake. - Open the IRISAgent logs (
docker compose logs irisagent) and copy thewireguard public key:line. Send it together withDEPLOYMENT_NAMEandSERVER_STATIC_IPto Vereign (kalin.canov@vereign.com) so they can register your peer on the CA side. - After Vereign confirms registration, complete
/onboardingin the dashboard to issue the S/MIME certificate.
For any additional peer (peer-to-peer between two Stargates), exchange public keys + endpoints with the other party and add the connection through the IRISAgent API:
curl --location 'localhost:8083/v1/connections' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"allowedIps": "<IP of new peer>/32",
"description": "<short description>",
"endpoint": "<IP of new peer>:19818",
"externalId": [
"<domain of new peer>"
],
"name": "<Name of new peer>",
"presharedKey": "",
"publicKey": "<public key of new peer>",
"status": "completed",
"transport": "tcp",
"wireguardIp": "<IP of new peer>",
"wireguardPort": 10080
}'
WireGuard Verification¶
Check IRISAgent WireGuard interface
Check connection in database
docker exec stargate-postgres psql -U postgres -d irisagent \
-c "SELECT connection_id, name, endpoint, wireguard_ip, transport, status FROM connections;"
Check connection external IDs (used for routing)
docker exec stargate-postgres psql -U postgres -d irisagent \
-c "SELECT connection_id, external_id FROM connection_external_ids;"
Test WireGuard connectivity (check tunnel status from host)
Check IRISAgent logs for tunnel activity
WireGuard Troubleshooting¶
No WireGuard interface:
- Check IRISAgent logs:
docker logs stargate-irisagent - Verify
WG_LOCAL_IPis set in.env(auto-derived fromSERVER_STATIC_IP— should be this server's static public IP)
Peer not reachable:
- Verify remote endpoint is accessible:
nc -zv <endpoint_host> <endpoint_port> - Check firewall allows TCP+UDP port 19818
- Verify public keys match on both ends
- If TCP has issues, try setting
WG_TRANSPORT_MODE="udp"in customer-config.sh
Connection not in database:
- Re-run the dashboard's
/installationpage to re-establish the peer connection - Check irisagent logs:
docker logs stargate-irisagent
Policy Sync¶
The policy-sync service automatically syncs OPA/Rego policies from a Git repository to the PostgreSQL database.
How Policy Sync Works¶
block
columns 8
A:2 space B:2 space C:2
A["Git Repository
policies/
alpha/
outbound/
..."]
A-->B
B["policy-sync:
- Clone/Pull repo
- Parse .rego files
- Upsert to database
- Runs every 1h"]
B-->C
C["PostgreSQL
- policy database
- policies table"]
Policy Sync Configuration¶
Settings in customer-config.sh:
## Git repository containing policies (pre-configured with HIN Stargate policies)
POLICY_SYNC_REPO_URL="https://github.com/Health-Info-Net-AG/Stargate-policies.git"
## Optional: Authentication for private repos
POLICY_SYNC_REPO_USER=""
POLICY_SYNC_REPO_PASS=""
## Optional: Specific branch (default: main)
POLICY_SYNC_REPO_BRANCH=""
## Optional: Subfolder within repo containing policies
POLICY_SYNC_REPO_FOLDER=""
## Sync interval (default: 1h)
POLICY_SYNC_INTERVAL="1h"
Policy Sync Verification¶
Manual Trigger¶
To force an immediate sync:
Vault¶
Vault Mounts¶
Vault's API/UI port (8200) is not published to the host; access Vault via the CLI inside the container (see Manual Vault Operations below).
The following KV-v2 secret engines are created:
secret-smimekeys-clientsecret-policysecret-irisagentsecret-mxenginesecret-mtaconf
Manual Vault Operations¶
Databases¶
PostgreSQL databases created:
smimekeys_clientpolicyirisagentmxengine
Connect to PostgreSQL¶
Or connect externally
Policies (Rego)¶
MXEngine uses OPA/Rego policies stored in PostgreSQL to determine mail delivery strategy.
Recommended: Use policy-sync to automatically sync policies from a Git repository. See Policy Sync section.
View Current Policy¶
Policy Location¶
- MXEngine config:
POLICY_OUTBOUND: "outbound/delivery" - Database:
policydatabase,policiestable - Managed by:
policy-syncservice (syncs from Git repository)
Logs¶
Troubleshooting¶
Certificate issuance failed / WireGuard tunnel not established¶
This is the most common issue after initial installation. The S/MIME certificate cannot be issued because the WireGuard tunnel to the HIN CA is not established.
Symptoms:
- The dashboard's
/onboardingpage reports CSR submission failure - smimekeys-client logs show:
issue certificate error: certcatunnel: error sending request: irisagent: ... context deadline exceeded
Root causes (check in order):
- Peer not registered on HIN CA - Your WireGuard public key must be registered on the HIN side. Provide HIN with:
Along with your DEPLOYMENT_NAME, SERVER_STATIC_IP, and WG_INTERFACE_PORT (if changed from 19818).
-
Firewall blocking port 19818 - Ensure
19818/TCPis open both inbound and outbound on the Stargate server. -
Wrong hostname - If the Stalwart hostname is still set to the template default (
mail.example.com), update it via the dashboard's/mailpage.
After the issue is resolved:
Re-open the dashboard's /onboarding page to regenerate the CSR and resubmit it through the now-up tunnel.
See Step 5: WireGuard Peer Registration for the full process.
Vault is sealed after restart¶
Run the start script which handles unsealing:
Cannot pull images¶
Login to the registry:
Service won't start¶
Check logs:
Reset everything¶
Warning
These commands DELETE ALL DATA - use with caution!
You can only restore data if you perform backup operations before and save the backup in a safe place.
Files Structure¶
stargate/
├── backups/ # Full backups (gitignored)
│ └── *.tar.gz
├── config
│ ├── apisix
│ │ ├── apisix.yaml.template
│ │ ├── config.yaml
│ │ └── generated
│ │ └── apisix.yaml
│ ├── keycloak
│ │ ├── generated
│ │ └── realm-stargate.json
│ ├── nats
│ │ └── nats.conf
│ ├── nginx
│ │ ├── dashboard.conf
│ │ └── keycloak.conf
│ ├── alloy
│ │ └── config.alloy # Alloy log shipping config
│ └── vault
│ └── vault.hcl # Vault configuration
├── customer-config-prod.example.sh # Config template (copy to customer-config.sh)
├── customer-config.sh # Customer-specific settings (copied from the template)
├── docker-compose.yml # Main compose file
├── .env # Environment variables (generated by install.sh)
├── init
│ └── postgres
│ └── 01-create-databases.sql
├── scripts
│ ├── backup.sh # Full backup (DB, Vault, config, certs)
│ ├── gather-app-versions.sh # Collects app versions for node-exporter metrics
│ ├── health-check.sh # Comprehensive health check of all services
│ ├── init-keycloak.sh
│ ├── init-vault.sh # Vault initialization (used by vault-init container)
│ ├── install.sh # First-time installation (Docker, Vault). Domain/cert/peer setup happens in the dashboard afterwards.
│ ├── purge.sh # Delete all data (destructive!)
│ ├── restore.sh # Restore from backup archive
│ ├── send-logs-to-support.sh # Paste logs online and get a link that you will provide to support
│ ├── start.sh # Start services + unseal Vault
│ ├── stop.sh # Stop containers (preserves data)
│ └── update.sh
└── secrets/ # Created on first run (gitignored)
├── vault-keys.json # Vault unseal keys (BACK THIS UP!)
└── signing-key.csr # S/MIME certificate signing request
Quick Health & Log Checks¶
Run the comprehensive health check
This checks:
- All container statuses (running, healthy)
- Liveness endpoints (smimekeys-client, policy, irisagent, mxengine)
- Vault seal status
- PostgreSQL connectivity and all 4 databases
- MinIO health
- WireGuard tunnel status and peer handshakes
- Stalwart MTA (running, port 25, port 10026)
- Prometheus metrics endpoints
- Disk and memory usage
For manual log inspection:
Check logs (last 10 lines)
docker logs stargate-smimekeys-client --tail 10
docker logs stargate-policy --tail 10
docker logs stargate-irisagent --tail 10
docker logs stargate-mxengine --tail 10
Follow logs in real-time
Check all container statuses
Follow all containers logs in real-time
docker ps -a --format '{{.Names}}' | xargs -I {} sh -c 'docker logs --timestamps -f {} 2>&1 | sed "s/^/[{}] /"'
Provide logs to support¶
You can provide logs to our support via pastebin.hin-infra.ch, and CLI command:
Upload all containers logs:
Use our script:
Or execute manually:
docker ps -a --format '{{.Names}}' | xargs -I {} sh -c 'docker logs --timestamps {} 2>&1 | sed "s/^/[{}] /"' | curl https://pastebin.hin-infra.ch/ --data-binary @-
Tip
This operation can hit our upload limits - 20 Mb.
Use our script:
Or execute manually:
This is default
--tail 500 is the default value for our script, but you can still provide it.
Use our script:
Or execute manually:
Upload specific container logs:
Tip
This operation can hit our upload limits - 20 Mb. If it happens, try to reduce the log amount by setting a time limit or number of lines.
After that, you will receive a unique link in the format https://pastebin.hin-infra.ch/<20 symbols> that you can provide to support / ticket.
Warning
The expiration time is set to 30 days. If some parts of the logs or the logs themselves need to be saved for a longer period, please make sure you keep a copy of them.
Helm Deploy¶
Info
Coming soon
This file contains instructions for Helm deploy of the HIN MGW instance.
VM deployment
Stargate Azure deployment using an image¶
Deploy Stargate on Azure
Azure Port 25 (SMTP) Requirements¶
Warning
Before beginning installation on Microsoft Azure, review the following requirements related to outbound SMTP connectivity on port 25. Skipping this step may result in email delivery failures after installation.
Whether port 25 is available depends on your Azure subscription type:
Enterprise Agreement (EA) or MCA-E - Outbound SMTP on port 25 is not blocked. Note that external domains may still reject emails - this is outside Azure's control.
Enterprise Dev/Test - Blocked by default, but can be removed. To request removal, go to Diagnose and Solve > Cannot send email (SMTP-Port 25) in the Azure Virtual Network resource in the Azure portal.
All other subscription types - Blocked and cannot be unblocked.
Reference: Troubleshoot outbound SMTP connectivity in Azure
Get the image file¶
- Download the latest VHD image file. Please refer to VM Catalog
Upload the Azure VHD image file¶
- Navigate to https://portal.azure.com/#home
- Click Storage accounts.
- Select the storage account to use or create a new one.
- Click Block service and then Containers.
- Select the Container to upload the file to or create a new one if you do not have a Container.
- Click Upload and choose the VHD image file.
- Make sure that the Blob type is Page Blob.
Create the image¶
- Navigate to https://portal.azure.com/#home
- Click Images.
- Click Create.
- Choose the Resource group to be used or create a new one.
- Type a Name for the image.
- Choose OS type Linux and VM generation Gen 2
- At Storage blob, click browse and select the newly uploaded VHD image.
- Click Review and create.
- Click Create.
Create a VM¶
- Navigate to https://portal.azure.com/#home
- Click Virtual Machines.
- Click Create, and choose Virtual Machine from the drop-down menu.
- Choose the Resource group.
- Type a Name for the VM.
- At Image, click "See all images", click "My Images" and choose the new image that was created.
- Choose the VM size.
- Choose authentication type.
- Click Next: Disks
- Select OS disk size at least 20 GiB. Please refer to Server Requirements.
- Click Review + create
- Click Create
Find the public IP address of the new VM and add inbound firewall rules¶
- Navigate to https://portal.azure.com/#home
- Click Virtual Machines.
- Click on the new VM.
- You can see the public IP address under "Primary NIC public IP"
- Scroll down to Networking and click on it
- Click + Create port rule, Inbound port rule, Destination port ranges 25, Protocol TCP, name it SMTP, repeat the same step with Destination port range 1587 and name it mxengine
Install HIN Gateway¶
After the VM has been successfully created, proceed with the installation and onboarding steps as described in the provided instructions
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
Stargate VMware ESXi deployment using an image¶
Deploy Stargate on VMware
Get the image file¶
- Download the latest OVA (or OVF and VMDK if you prefer) image file. Please refer to VM Catalog
Navigate to the ESXi web UI¶
- Click Virtual Machines
- Click Create/Register VM
- Choose "Deploy a virtual machine from an OVF or OVA file"
- Click Next
- Type a name for the VM
- Click Next
- Click to select files and choose the OVA image file (or OVF and VMDK if you prefer)
- Click Next
- Choose a storage to use
- Click Next
- Choose Network and Disk for provisioning
- Click Next
- Click Finish
Install HIN Gateway¶
After the VM has been successfully created, proceed with the installation and onboarding steps as described in the provided instructions
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
Proxmox deployment using an image¶
Deploy Stargate on Proxmox
Get the image file URL¶
- Please refer to VM Catalog for a list of images with URLs.
- Copy URL to clipboard, for example
https://images.hin.ch/vm-images/Verimesh-HINGateway.v0.5.1.x86_64.qcow2
Import the image file in Proxmox¶
- In Proxmox WebUI, navigate to the Storage menu and click Import
- Click Download from URL, paste the copied URL and click "Query URL".
- Click Download and wait for "TASK OK" to appear at the end of the output log.
- Close the Task Viewer Download window.
Create a VM¶
- Click "Create VM"
- Type a name for the VM
- Click "Next"
- Choose "Do not use any media"
- Click "Next"
- Click "Next"
- Click the "Trash icon" next to "scsi0" to remove it.
- Click "Import" and under "Select Image", choose the newly imported image file.
- Click "Next"
- Select 4 CPU cores and choose your CPU Type (or use "host"). Please refer to Server Requirements.
- Click "Next"
- Select 8192 MiB Memory. Please refer to Server Requirements.
- Click "Next"
- Click "Next"
- Wait until the VM creation process finishes and then click on the new VM, click "Console", click "Start Now"
Install HIN Gateway¶
After the VM has been successfully created, proceed with the installation and onboarding steps as described in the provided instructions
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
Windows 11 Pro deployment using an image¶
Deploy Stargate on Windows Pro (non-Pro versions do not support Hyper-V)
Install Hyper-V¶
- Click the Start button, then type "Turn Windows features on or off"
- Click on that button
- Check Hyper-V and click "OK"
- After the installation completes, click "Restart now" and wait for Windows to boot again
Note: We recommend deploying the VM using Hyper-V Generation 2
Get the image¶
- Download the .vhdx image file. Please refer to VM Catalog
Import the image file and create a VM with it¶
- Click the "Start" button and type "Hyper-V Quick Create"
- Click on that icon
- Choose "Local installation source"
- Uncheck "This machine will run Windows"
- Click "Change installation source", navigate to the downloaded .VHDX image and click on it
- Click "Create virtual machine"
- Click "Edit settings"
- Under "Memory", choose "RAM" 8192 MB. Please refer to Server Requirements.
- Under "Processor", choose "Number of virtual processors" 4. Please refer to Server Requirements.
- Click "OK"
- Click "Connect"
- Click "Start"
Install HIN Gateway¶
After the VM has been successfully created, proceed with the installation and onboarding steps as described in the provided instructions
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
Stargate Deployment on Cloudscale Using an Image¶
Get the Image File URL¶
- Refer to the VM Catalog for available images with URLs.
- Copy the
qcow2URL to your clipboard.
Import the Image File in Cloudscale¶
- In the Cloudscale WebUI, navigate to the "Custom Images" menu and click "Import a Custom Image".
- Set an appropriate Image Name.
- Define a Slug, e.g., "stargate".
- Paste the Stargate image URL into the Download URL field.
- Set Source Format to the upload format, recommended:
qcow2. - Configure additional settings as needed.
- Click Import.
Create a VM¶
- Navigate to Servers and click Launch a new Server.
- Enter your preferred FQDN or hostname.
- Under Operating System, select Custom Images and choose your imported image.
- Under Compute Flavor, select Flex-4-2 or Flex-8-2 depending on expected load (can be adjusted later). See Server Requirements for details.
- Under Storage Capacity, set at least 30 GB. Please refer to Server Requirements.
- Under Server Location, select your preferred zone.
- Under Network Management, enable only IPv4 if the Stargate instance must be internet-accessible (e.g., for Office 365).
- Under Access Security, select your SSH key (usable with the
almalinuxuser). - Under Password, set any secure password you prefer.
Without a password, SSH password authentication is disabled
You must still use the initial password provided by HIN for your first login. However, if you do not set a new password, cloud-init will disable SSH password authentication for all users, allowing SSH access only via public key authentication.
- Click Launch.
Install HIN Gateway¶
After the VM has been successfully created, proceed with the installation and onboarding steps as described in the provided instructions
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support.
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.
VM Images Catalog¶
Here you can find a current VM Catalog for different platforms. Please do not forget to check the SHA-256 hash of downloaded images. You can use the https://images.hin.ch/vm-images/SHA256SUMS file to compare it.
How to perform SHA256 hash check locally
You can calculate the SHA256 hash of downloaded files with the following command and then compare it with the values in the table below.
Open Terminal and execute:
As a more advanced variant, you can execute the following command and paste the predefined checksum as SHA256_VALUE and the file name as IMAGE_NAME:
| Image Name | Image Type | Image Size | Link | SHA256 Checksum |
|---|---|---|---|---|
hingateway-v0.5.3.x86_64.ova |
981M / 1028392960 bytes |
Download | 332e81d4a3c7bca0da94fb337793bbd5a30e204d2d524086ff7aad9945dc78a6 |
|
hingateway-v0.5.3.x86_64.mf |
4.0K / 227 bytes |
Download | dfcbba5bcf4066732e32a7753388ce27d1b04e01528d9103934992273b97dbd5 |
|
hingateway-v0.5.3.x86_64.ovf |
8.0K / 7670 bytes |
Download | 44c5343e2dd5bb8b371b1aaf2e98e60fd4d4cf42f0989b596144f68be9dd2e1e |
|
hingateway-v0.5.3.x86_64.qcow2 |
1.6G / 1686503424 bytes |
Download | c25cfdc497af7ac49caf04d62c8f4b0adcbeb1f0c55a29b74e67b70c4770f81d |
|
hingateway-v0.5.3.x86_64.raw |
30G / 32212254720 bytes |
Download | 6de4925c8502d0dff690d7c74e2a6004e53e3c54444eb128db788c2aff754828 |
|
hingateway-v0.5.3.x86_64.raw.gz |
989M / 1036406461 bytes |
Download | 9ec2815ee6a575018630a6c6abfa44df2291594562e53fe7b0f4f74c5ffa5f0c |
|
hingateway-v0.5.3.x86_64.vhd |
31G / 32212255232 bytes |
Download | f1bdc4afebb6b8c7234bc4dc915803ce0d4939539c761f1eaea2da4f27833fcd |
|
hingateway-v0.5.3.x86_64.vhd.gz |
1004M / 1052039565 bytes |
Download | 0a011435938e727fac7039c9384a7be6abc8f32d361f36733943fa4b89c3a882 |
|
hingateway-v0.5.3.x86_64.vhdx |
2.2G / 2256535552 bytes |
Download | 958da9752f3c06856d25ecf917852e003ba55ae21f244c4f2e1ee76646ec20f0 |
|
hingateway-v0.5.3.x86_64.vmdk |
981M / 1028378624 bytes |
Download | 1954651e722f0aa9280fa85902e64af6a255dc63b63111904c023c0518bc9ff3 |
|
SHA256SUMS |
4.0K / 979 bytes |
Download | 9514d4671a7e33e9e924029752a6f6bb31a4209a7999ba3f72e119215f4e03b9 |
Troubleshooting & Diagnostics¶
A structured guide to diagnosing a Stargate appliance from the command line: what to check, where the logs are, and safe recovery actions.
Where to run these commands
Run everything below from the deployment directory - the folder containing docker-compose.yml and scripts/ (on VM images this is typically /root/stargate-deployment/docker-compose, or the directory you installed into). All docker compose and ./scripts/* commands assume that working directory.
1. Start here: the health check¶
One command summarizes the whole appliance:
It reports pass/fail for: containers (running/healthy), liveness endpoints (smimekeys, policy, irisagent, mxengine), Vault seal status, PostgreSQL connectivity + databases, SeaweedFS, the WireGuard tunnel + peer handshakes, Stalwart MTA (ports 25 / 10026), Prometheus metrics endpoints, and disk / memory.
Tip
Run this first. A single FAIL line usually points you straight at the section below.
2. Where the logs are¶
| Layer | Command | What it shows |
|---|---|---|
| Boot / first-install / auto-start | sudo journalctl -u stargate -n 200 --no-pager |
The systemd service that runs start.sh on boot and the first-boot install |
| Update runs | cat ../update.log (deployment root, one level above docker-compose/) |
Output of the last dashboard/host-triggered update.sh |
| A single service | docker logs stargate-<service> --tail 100 |
e.g. stargate-dashboard, stargate-mxengine, stargate-keycloak |
| Follow one service live | docker logs -f stargate-mxengine |
Real-time |
| All containers live | docker ps -a --format '{{.Names}}' \| xargs -I{} sh -c 'docker logs --timestamps -f {} 2>&1 \| sed "s/^/[{}] /"' |
Merged, prefixed by container |
| Web log viewer | Dozzle at https://<SERVER_IP>:8190 (Keycloak login) |
Browse all container logs in a UI |
To hand logs to HIN support, use the upload script and share the returned link - see Provide logs to support:
3. Containers not running or restarting¶
Read the Status column:
| Status | Meaning | Action |
|---|---|---|
Up ... (healthy) |
Running fine | - |
Up ... (no health) |
Running; no healthcheck defined | Check its docker logs if you suspect trouble |
Restarting |
Crash-looping | docker logs stargate-<svc> - fix the root error (config, secret, dependency) |
Exited (0) |
One-shot init finished OK (e.g. *-init, vault-data-fixer) |
Normal |
Exited (1+) |
Failed | docker logs stargate-<svc> - the last lines show why |
Created |
Never started - a dependency didn't come up | Check what it depends_on (usually Postgres/Vault); fix that first |
Restart a single service (safe, non-destructive):
docker compose up -d <service> # recreate one service
docker compose restart <service> # just restart it
Startup order
Services wait on their dependencies (depends_on + healthchecks). During a full restart, brief connection refused / database system is starting up lines while Postgres/Vault come up are normal and clear within a minute.
4. Diagnose by symptom¶
Dashboard or Keycloak won't load / can't log in¶
- Both are fronted by Caddy: Dashboard on
:443, Keycloak on:8180. - Check the chain:
docker logs stargate-caddy,stargate-dashboard,stargate-keycloak,stargate-apisix. - Keycloak must be healthy before the dashboard works:
docker compose ps keycloak. - TLS warning in the browser is expected (self-signed cert) - accept and proceed.
- Login redirects failing usually mean the public URL doesn't match how you reach the box - verify
KEYCLOAK_PUBLIC_URL/DASHBOARD_PUBLIC_URLin.envpoint at the IP/host you actually use.
WireGuard tunnel down / certificate issuance fails¶
This is the most common issue - certificates fail when the tunnel is down, so always fix the tunnel first.
./scripts/health-check.sh -v # shows WireGuard peer + handshake status
docker logs stargate-irisagent | grep -iE "handshake|peer|cert|wireguard"
- Confirm the firewall allows
19818(UDP and TCP) inbound/outbound. - Verify the peer is registered on the HIN side (support step) - you supply WG public key,
DEPLOYMENT_NAME,SERVER_STATIC_IP,WG_INTERFACE_PORT. - Once the tunnel shows a recent handshake, retry certificate issuance from the dashboard.
Vault sealed or init failed¶
- Vault must be unsealed for smimekeys/mxengine/policy to work. Keys live in
secrets/vault-keys.json. - If
vault-initexited non-zero, the keys file may be missing/corrupt - check its logs; re-running./scripts/init-vault.shre-attempts unseal.
Do not delete secrets/vault-keys.json
Losing it means losing access to all stored secrets. Keep a backup.
PostgreSQL / database connectivity¶
- Transient
the database system is starting up (57P03)right after a restart is normal - services reconnect automatically. - Persistent auth failures usually mean
POSTGRES_PASSWORDin.envdrifted from the data volume - see the update/secrets notes, and avoid editing it by hand.
Mail not flowing¶
-
Inbound arrives on
:25(Stalwart). Many cloud providers block port 25 by default:If
25is blocked, request an exception from your provider. - Outbound / sealing goes Stalwart → mxengine (:8084seal callback, SMTP:1587):docker logs stargate-mxengine. - Mail loops show as the same message cycling - check that your domain's MX does not resolve back to this appliance's own IP. - See Mail relay setup and DNS setup for the expected routing.
An update failed¶
docker logs stargate-ops-agent --tail 40 # the update orchestrator
cat ../update.log # the update script output
- The ops-agent pulls the release manifest, writes versions to
customer-config.sh, then runsupdate.shon the host. - After it finishes, confirm versions applied:
./scripts/gather-app-versions.sh(or checkdocker compose psimage tags). - If a service is stuck after an update,
docker compose up -d <service>to recreate it.
Update starts but nothing happens (updating from an older version). If the ops-agent log stops at pulling deployment repo ... and the update never proceeds, the repository on the VM most likely has local edits to a tracked file (commonly a hand-patched docker-compose.yml). That makes the ops-agent's git checkout refuse to run, so the update stalls. Force-reset the repository to the latest revision, then re-run the update. Git is the single source of truth; this discards local edits to tracked files only - customer-config.sh, .env, and secrets/ are gitignored and preserved:
cd /root/stargate-deployment
git fetch origin
git checkout -f main
git reset --hard origin/main
sed -i 's/^OPS_AGENT_VERSION=.*/OPS_AGENT_VERSION="v0.0.3"/' docker-compose/customer-config.sh # v0.0.3 or newer
cd docker-compose
./scripts/update.sh
update.sh regenerates .env, pulls the images, and recreates the affected services - you do not need to restart Stargate manually. When it completes, retry the update from the dashboard; it will now proceed.
Warning
Do not use git pull here. On a working tree with local edits it aborts with "local changes would be overwritten", which forces a git stash / merge-conflict / manual-recovery detour. The git checkout -f + git reset --hard sequence above avoids that entirely and is the safe, repeatable way to bring the repo current.
Dozzle (log viewer) not reachable¶
- URL is
https://<SERVER_IP>:8190; it requires a Keycloak login (same realm as the dashboard) via oauth2-proxy. - It only runs when
DOZZLE_ENABLED="true". Check:docker compose ps dozzle oauth2-proxy. - Ensure the firewall allows
:8190inbound. See Monitoring and Logs.
5. Storage & disk¶
df -h / # is the disk full?
docker system df # space used by images / containers / volumes
du -sh /var/lib/docker/volumes/* # per-volume usage (Postgres, SeaweedFS, Loki, ...)
- Container logs are capped (json-file, 100 MB × 5 per container) so they shouldn't fill the disk, but images and volumes can.
- Reclaim space safely:
docker image prune -af(removes unused images only). Avoiddocker system prune --volumes- it deletes data volumes. - Object storage is SeaweedFS (
stargate-seaweedfs):docker logs stargate-seaweedfs --tail 50.
6. VM resources¶
free -h # memory (min 8 GB)
nproc # CPUs (min 4)
docker stats --no-stream # per-container CPU/RAM
uptime # load average
Host metrics are also exported for Prometheus on :9100/metrics (see Monitoring). If the box is swapping or pegged, expect healthchecks to flap and updates to be slow.
7. Network & ports¶
Quick reachability check for the key inbound ports:
| Port | Service | Direction |
|---|---|---|
25 |
Stalwart SMTP (inbound mail) | inbound |
443 |
Dashboard (HTTPS) | inbound |
8180 |
Keycloak | inbound |
8190 |
Dozzle (optional) | inbound |
8084 |
mxengine seal callback | inbound |
19818 |
WireGuard (UDP and TCP) | in/outbound |
Outbound access is needed to the container registry, the S/MIME CA (over the WireGuard tunnel), and any remote Loki you configured. See the full port table on the home page and Applications overview.
8. Recovery actions¶
Ordered least- to most-disruptive:
docker compose up -d <service> # recreate one stuck service
sudo systemctl restart stargate # restart the whole stack (via start.sh)
./scripts/stop.sh && ./scripts/start.sh
Backups & destructive recovery
./scripts/backup.sh and ./scripts/restore.sh handle data backup/restore. ./scripts/purge.sh deletes all data (databases, Vault, storage) for a clean reinstall - use only as a last resort and only with a current backup. Details: Docker Advanced configuration.
9. When to contact support¶
If the health check still shows failures after the steps above, open a ticket via Support / Contact us and include:
- The appliance version (
./scripts/gather-app-versions.sh) and customer name. - The health-check output (
./scripts/health-check.sh -v). - A log bundle link from
./scripts/send-logs-to-support.sh(see Provide logs to support). - What you were doing when it broke, and any screenshots.
Update Verimesh Instance¶
The following instructions describe how to update a Verimesh instance from v0.5.1 to v0.5.3.
Note: You will need to login to the VM using the Linux administrator account.
Update Steps¶
- Edit the .env file and update the ops-agent version to v0.0.3.
- Edit the customer configuration and update the ops-agent version to v0.0.3 there as well.
- Switch to the main branch:
git checkout main - Pull the latest changes:
git pull - Update the ops-agent container:
docker compose up -d ops-agent - Log in to the Dashboard.
- Navigate to Settings.
- In the Update section at the bottom of the page, enter the target version (v0.5.3) and start the update process.
Setup updated keycloak¶
Note: This instructions is valid if you are running on VM image v0.5.1 and then you updated to newer version.
After the latest Keycloak update, a breaking change causes authenticated users to be unexpectedly redirected to the login page when navigating to specific application routes (e.g., Peers, Peer Certificates).
To resolve this, the following manual configuration must be completed in the Keycloak UI.
Resolution Steps¶
-
Open the keycloak on the env and put in the url -
<VM IP address>/admin/master/console/user: Admin pass: get the admin pass from the .env of the machine (you need to login on linux console) -
Admin console - change realm to → realm stargate:
- Go to Clients → dashboard
- Navigate to the Client scopes tab → click dashboard-dedicated
- Select Configure a new mapper → Audience
-
Set the following configurations:
- Name: apisix-audience
- Included client audience: apisix (select from dropdown)
- Included custom audience: (leave empty)
- Add to access token: On
- Add to token introspection: On
- Add to ID token / lightweight token: Off
-
Click Save
Release Notes¶
v0.5.3¶
...
v0.5.1¶
Our initial release.
Contact us¶
Support
For any questions or issues related to the deployment and operation of the Stargate appliance, please contact HIN support by email, phone:
You can find more information in our Contact page: https://support.hin.ch/de/kontakt.cfm
Please include relevant information such as the customer name, appliance version, and screenshots/logs where applicable, to help us process your request efficiently.













































