Skip to content

Installation

This guide walks through a fresh install on a clean Ubuntu 24.04 VPS. The full path is prerequisites → download → install → publish DNS records, and the curl | sudo bash one-liner is interactive — you’ll be prompted to confirm the hostname and admin email it auto-detects from your VPS’s reverse DNS.

  1. Prerequisites — enable SSH on the VPS, update Ubuntu, set reverse DNS (PTR), and request port 25 unblock from your provider.
  2. Download — run curl -fsSL https://get.vectismail.com | sudo bash. The script places the binary, installs Docker if missing, and seeds secrets.
  3. Preflight — run vectis preflight to confirm OS version, ports, and Docker are ready.
  4. Install — run vectis install to deploy the stack, run database migrations, and create the admin account.
  5. Publish DNS records — A record at your registrar; PTR at your VPS provider.
  6. Verify the installvectis status plus a successful login at https://your-mail-host/admin.

Before running the installer, make sure your VPS is in the right state.

Many VPS providers (BinaryLane and Hetzner among them) ship Ubuntu images with password-based SSH disabled — /etc/ssh/sshd_config ships with PermitRootLogin prohibit-password, and no non-root user is created. If you try to ssh root@your-vps immediately after provisioning, the connection will be refused.

You have two options:

(a) Add your SSH public key at the provider’s panel. Most providers let you paste a key into the VPS config before (or shortly after) it boots. With the key installed, ssh root@your-vps works immediately, and nothing else is needed here.

(b) Use the provider’s web console to create a sudo user and enable password SSH. Open the web console (BinaryLane calls it “VNC”; DigitalOcean “Droplet Console”), log in as root with the initial password the provider emailed you, then:

Terminal window
# Create a non-root user with sudo
adduser vectis
usermod -aG sudo vectis
# Allow password-based SSH for this user (optional — key-based is preferred)
# Edit /etc/ssh/sshd_config: set "PasswordAuthentication yes"
sudo systemctl reload ssh

You only need this step once. Everything else in this guide assumes you can SSH into the box.

On a fresh VPS, bring the base packages up to date:

Terminal window
sudo apt update && sudo apt upgrade -y

If a kernel upgrade is included, reboot before continuing:

Terminal window
sudo reboot

3. Set reverse DNS (PTR) at your VPS provider

Section titled “3. Set reverse DNS (PTR) at your VPS provider”

PTR (reverse DNS) is a hard requirement, not a nice-to-have. Without a matching PTR record, your outbound mail will be rejected as spam by Gmail, Outlook, and most receiving servers — and the deliverability check in the Setup Wizard will fail.

Do this at your VPS provider’s control panel (BinaryLane, Hetzner, DigitalOcean, etc.) — not at your DNS registrar. Some providers expose it as a simple field; others require a one-time support request (same channel as the port 25 unblock below). The PTR record for your server’s public IPv4 should resolve to the FQDN you intend to use for mail (e.g. mail.example.com).

Verify it from any machine once set:

Terminal window
# Expect output like: 203.0.113.10.in-addr.arpa name = mail.example.com.
dig -x YOUR_SERVER_IP +short

The installer looks this up for you and, if it resolves, pre-fills your mail-server hostname automatically — you just press Enter. If PTR isn’t set when you run the installer, you’ll have to type the hostname manually and fix the PTR afterwards.

Most VPS providers block outbound port 25 by default to prevent spam abuse. Without it, your server can send to itself but not to anyone else. Check your provider’s documentation for “SMTP unblock” or “port 25 unblock” — usually a one-time support request.

ResourceMinimumRecommended
OSUbuntu 24.04 LTSUbuntu 24.04 LTS
CPU2 vCPU4 vCPU
RAM2 GB (without ClamAV)4 GB+
Disk30 GB SSD allocation (~20 GB free after OS install)100 GB+ SSD
Inbound ports25, 80, 443, 465, 587, 993, 995+ IPv6

Docker is installed automatically by the script if it isn’t already present.

From v0.1.13, Vectis applies per-container memory ceilings keyed off a resources.profile knob in /etc/vectis/config.yaml. Limits are hard cgroup ceilings — if a service tries to exceed its limit, only that container’s cgroup OOM-kills it, never the whole host. Pick the profile that matches your VPS RAM; the installer defaults to small for a 4 GB VPS.

ProfileBase install+ Webmail + Loki/Promtail/Grafana+ ClamAV smallSuits
dev~1.8 GB~2.6 GB~3.6 GBLaptop / 2 GB VPS
small (default)~3.5 GB~4.6 GB~6.1 GBSingle-domain 4 GB VPS
production~6.7 GB~8.0 GB~10 GBMulti-domain 8 GB VPS
enterprise~13.5 GB~16.5 GB~19.5 GBHigh-volume 16 GB+

“Base” is postgres + valkey + api + orchestrator + traefik + postfix + dovecot + rspamd — the always-on services. Each optional service (webmail, observability stack, ClamAV, pgbouncer, cert-extractor) adds its own profile-scaled ceiling on top.

To switch profile after install: edit /etc/vectis/config.yaml, change resources.profile, then vectis update apply. The brief container restart that follows picks up the new ceilings.

Run the one-liner. It downloads the binary, installs Docker if needed, seeds randomly-generated secrets, and prompts you to confirm the hostname.

Terminal window
curl -fsSL https://get.vectismail.com | sudo bash

You’ll see prompts like:

[INFO] Detected public IPv4: 203.0.113.10
[INFO] Reverse DNS (PTR): mail.example.com
Mail server hostname [mail.example.com]:
TLS / admin email [[email protected]]:

Press Enter to accept the defaults the script detected, or type to override. If your VPS doesn’t have PTR set, the prompt defaults to a placeholder and you’ll need to type your FQDN manually.

When the script finishes you’ll see:

========================================================
Vectis downloaded successfully
========================================================
The binary is in place but nothing is running yet. Next steps:
1. Review /etc/vectis/config.yaml (hostname: mail.example.com)
2. vectis preflight # verify system + ports + DNS
3. vectis install # deploy containers, run migrations, create admin

This step only puts the binary on disk — it doesn’t start anything. The next two steps do.

What if I want to run it non-interactively?

Section titled “What if I want to run it non-interactively?”

Pipe the script with no TTY (e.g. unattended cloud-init), and it’ll skip the prompts. It writes the detected PTR if there is one, or leaves the placeholder for you to edit /etc/vectis/config.yaml by hand. The next step (vectis install) will refuse to proceed if it finds the placeholder.

Verify the system is ready:

Terminal window
vectis preflight

This checks OS version, CPU/RAM, port availability (25, 80, 443, 465, 587, 993, 995), outbound port 25 reachability, Docker version. Anything red here will block install — fix and re-run.

Terminal window
vectis install

This is the heavy lift — about 11 steps over 1-3 minutes depending on your network speed. It generates service configs, writes the docker-compose file, pulls all images, brings Postgres up first and waits for it to be healthy, runs database migrations, creates the initial admin account, then starts the rest of the stack.

When it finishes you’ll see:

═══════════════════════════════════════════
Vectis is ready!
Admin URL: https://mail.example.com/admin
Admin email: [email protected]
Admin password: a3f9c2b1e5d7891f
!! SAVE THE PASSWORD ABOVE — it is shown only here, it is
not written to disk, and it will not be recoverable.
Change it immediately after your first login.
DNS records you must publish now:
...

Copy the admin password before closing the terminal. It is only ever shown here. The plaintext is not written to disk anywhere — only its bcrypt hash. If you’re running the installer in a VPS-provider web terminal, scrollback may be limited or absent, so copy immediately.

If you closed the terminal before copying it, generate a new one with:

Terminal window
docker run --rm \
--network vectis_vectis-data \
-v /etc/vectis:/etc/vectis:ro \
--entrypoint vectis \
ghcr.io/veltara-works/vectis-api:latest \
admin reset-password [email protected]

Output includes the new password — copy it once and use it to log in.

Why not docker compose run? A Compose v5.x bug silently disconnects the live vectis-api container from its internal Docker networks during the transient-container handoff. The plain docker run --network form above bypasses that interaction and is safe to repeat.

The install banner prints the records you need to publish. There are two destinations:

At your domain registrar (or Cloudflare if your nameservers point there):

A mail.example.com. → 203.0.113.10

If you also have IPv6 and the v6 PTR matches your hostname, the banner will additionally print an AAAA record. If your v6 PTR isn’t set or doesn’t match, the banner will explicitly tell you not to publish AAAA — Gmail and Outlook reject IPv6 mail with mismatched PTR.

At your VPS provider’s control panel (NOT the registrar):

PTR 203.0.113.10 → mail.example.com.

You should already have this set as a prerequisite. If you didn’t, do it now — outbound mail will be rejected as spam without it.

The per-domain MX, SPF, DKIM, and DMARC records come from the Setup Wizard in the admin UI once you log in — those are scoped to each mail-domain you add (e.g. example.com if you want to send [email protected]), not the server’s hostname.

Terminal window
# All containers healthy
vectis status
# Admin UI loads
# https://mail.example.com/admin
# (allow a minute or two for Let's Encrypt to issue the cert)

Once the cert has issued, opening the admin URL in your browser should show the login screen:

Vectis Mail admin login screen

Sign in with the admin email and password from the banner. From here, the Your First Domain guide walks through the Setup Wizard to add a domain and create your first mailbox.

If the admin URL refuses to connect from your laptop:

  • Check the public IP path: curl -v -4 http://YOUR_IP/ should reach Traefik (a 404 with Host: localhost is expected)
  • If it doesn’t, your VPS provider may have an inbound firewall — check their panel for any “Cloud Firewall” / “Network Firewall” / security group rules

After install, your config lives in /etc/vectis/:

FilePurpose
config.yamlSystem configuration (hostname, TLS, resources, features)
secrets.yamlCredentials (database, API, DKIM paths, OIDC, ValidonX)

The generated docker-compose file lives at /etc/vectis/docker-compose.yml, and the rendered service configs at /var/vectis/generated/.

Changes to config.yaml are applied via:

Terminal window
vectis config apply

This regenerates affected service configs and reloads the relevant containers.