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).
  • 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.

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)

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.