Running Xeams as a Non-Root User on Linux

A guide to why Xeams should not run as root on Linux, and how to migrate an existing installation to a dedicated, unprivileged service account.

Why this matters

Older Linux installations of Xeams ran the application as the root user. This was originally necessary because Xeams' SMTP service listens on privileged ports below 1024 (most notably port 25), and on Linux only root is normally allowed to bind those ports. Running the entire mail server process as root, however, is more privilege than the application actually needs, and it carries real risk.

The benefits of a non-root service account

BenefitExplanation
Reduced blast radius If Xeams, a library it depends on, or a plugin were ever compromised, the attacker only gains the privileges of the unprivileged service account — not full control of the machine.
Principle of least privilege Xeams only actually needs one narrow capability: the ability to bind ports below 1024. Modern Linux lets you grant exactly that one capability to a process without granting root, via systemd's AmbientCapabilities.
Safer file system access A non-root Xeams process can only read and write files it has explicitly been given permission to, limiting the damage from bugs, misconfiguration, or malicious email content.
Compliance and security audits Many security review checklists and compliance frameworks flag any long-running network-facing service that executes as root. Running Xeams as a dedicated account removes this finding.
Consistent with modern best practice Nearly every production-grade Linux service (nginx, Postfix, MySQL, PostgreSQL, etc.) runs under its own unprivileged system account. Xeams follows the same model.
What makes this possible: Linux capabilities let the operating system grant a process one narrow privilege — in this case CAP_NET_BIND_SERVICE, the ability to bind ports below 1024 — without granting full root access. systemd can apply this capability automatically whenever the service starts, so Xeams keeps the ability to listen on port 25 while running as an ordinary, unprivileged user for everything else.

Before you begin

  • This migration applies to Linux installations that use systemd (the default init system on current Ubuntu, RHEL, CentOS, Rocky Linux, Fedora, Debian, and Linux Mint releases).
    Important: You must use systemd version 229 or above (released March 2016). Older versions of systemd do not support the AmbientCapabilities feature. Run the following command to check the version of systemd:
    systemctl --version
    # or
    rpm -q systemd        # RHEL/CentOS/Fedora
    dpkg -s systemd | grep Version   # Debian/Ubuntu
  • You do not need to stop Xeams manually first — the migration script stops the old service for you as part of the process.
  • No configuration, mail data, logs, or TLS certificates are modified. The only exception: if the ntServiceCommand setting in config/AppConfig.xml is currently blank, it will be set so that Xeams' own "restart myself" feature keeps working once it is no longer running as root. An existing non-default value is left untouched.
  • You will need root (or sudo) access to run the migration script.
  • Xeams will be briefly unavailable — typically a few seconds — while the service is stopped and restarted under the new account.
Already running as non-root? The migration script detects this automatically and will refuse to run, since there is nothing left to migrate.
Older installations only: some older root-based installs have ntServiceCommand set to /etc/init.d/xeams start in config/AppConfig.xml. That value only works with the old init.d-based setup being replaced, and the migration script only fills in ntServiceCommand automatically when it is blank — it will not overwrite an existing custom value. If your installation has this old value, clear it back to blank before running the migration script, so the script can set the correct systemd-based command for you:
sed -i "s:<ntServiceCommand>/etc/init.d/xeams start</ntServiceCommand>:<ntServiceCommand></ntServiceCommand>:" /opt/Xeams/config/AppConfig.xml
Adjust the path if Xeams is installed somewhere other than /opt/Xeams. This command only matches that exact old value, so it is safe to run even if the field is already blank or already holds something else — in either case it simply won't match and nothing will change.
Download Migration Script

How to migrate an existing installation

  1. Log in to the Xeams server and obtain root privileges:

    sudo -i
  2. Download ChangeToNonRoot.sh to the server, then make it executable:

    chmod +x ChangeToNonRoot.sh
  3. Run the script:

    ./ChangeToNonRoot.sh
  4. Read the introductory banner, which explains exactly what the script will and will not do, then confirm to proceed:

    Continue? [y/N]: y
  5. Confirm (or change) the existing Xeams installation directory. The default is /opt/Xeams:

    Existing Xeams installation directory [/opt/Xeams]: 
  6. Choose the OS user Xeams should run as. The default is xeams, and the script creates this account for you (with a proper home directory) if it doesn't already exist:

    OS user to run Xeams as [xeams]: 
  7. The script then automatically:

    • Stops and removes the old root-based service registration (systemd unit and/or /etc/init.d/xeams).
    • Creates the non-root service user and hands it ownership of the install directory.
    • Writes a new systemd service that runs Xeams as that user, granting it CAP_NET_BIND_SERVICE so it can still bind privileged ports such as SMTP port 25.
    • Installs a narrowly-scoped sudoers rule so Xeams' built-in restart feature keeps working under the new account.
    • Replaces the old Uninstall.sh (which only knew how to remove the root-based service) with one that matches the new non-root setup, preserving the original as Uninstall.sh.old.
    • Starts the new service and reports whether it came up successfully.

Verifying the migration

Confirm the service is active and running under the new account:

systemctl status xeams.service

Confirm the process itself is owned by the new user, not root:

ps -o user,pid,cmd -C java

Confirm Xeams is still reachable on its usual ports (including SMTP port 25) and that the web interface loads normally.

Managing the service afterwards

ActionCommand
Startsystemctl start xeams.service
Stopsystemctl stop xeams.service
Restartsystemctl restart xeams.service
Statussystemctl status xeams.service
View logsjournalctl -u xeams.service -n 50
Uninstall/opt/Xeams/Uninstall.sh (path may differ if you installed elsewhere)

Post Migration Steps

In most cases, the migration script is all you need to run. However, there may be instances where additional steps are needed.

  • AppConfig.xml - The AppConfig.xml file stored in the $INSTALL_DIR\config folder contains a parameter called ntServiceCommand. The value of this parameter must be sudo /usr/bin/systemctl restart xeams.service. The script only modifies the AppConfig.xml file if this field was originally blank. Therefore, confirm this parameter has the correct value after migration.
  • External folders - The default behavior in Xeams is to store every file in the $INSTALL_DIR folder. However, administrators can move some folders to a different location when disk space is low. In such cases, you will need to change the ownership of those folders to the new 'xeams' user. For example:
    • Temp folder
    • Good Emails
    • Spam Email
    • Possible Spam

Frequently asked questions

Will this change my configuration, mail data, or certificates?
No. The migration only changes how the process is launched and who owns the files on disk. The one narrow exception is described above: a blank ntServiceCommand setting may be populated so self-restart keeps working.
Can Xeams still bind port 25 without root?
Yes. The generated systemd service grants the process CAP_NET_BIND_SERVICE, a targeted Linux capability that allows binding ports below 1024 without full root privileges.
What if I installed Xeams somewhere other than /opt/Xeams?
The migration script prompts for the installation directory and defaults to /opt/Xeams, but you can point it at any existing installation path.
What if systemd isn't available on my system?
The migration relies on systemd's AmbientCapabilities to grant the privileged-port permission. If systemd is not detected, the script exits without making any changes, and Xeams continues running as it did before.
After migration, I am unable to restart Xeams from the web interface. Why?

Ensure the value of ntServiceCommand in $INSTALL_DIR\config\AppConfig.xml is set to:

sudo /usr/bin/systemctl restart xeams.service

and the absolute path refering to systemctl is correct on your machine.