Tracking domain & VPN
Open tracking, click tracking and unsubscribe links in your emails have to be reachable by the people you email — from anywhere on the internet. The rest of SubsiMail (the login, your contacts, everything) doesn't. A tracking-only port lets you keep the app private while the tracking links stay public.
Why a separate tracking port
SubsiMail listens on a second port, 3001 by default (the app's port plus one; set TRACKING_PORT to change it, or TRACKING_PORT=off to turn it off). It serves only the open pixel, the click redirect and the unsubscribe page, plus a tiny "check" answer. None of the app exists on it — no login page, no dashboard, no API — so exposing it can't expose your data, and there's nothing to misconfigure into the open.
Set it up
- Pick a tracking domain, for example
t.yourcompany.com, and point its DNS at your server. - Put a reverse proxy in front of the tracking port that serves that domain over HTTPS (examples below). With Docker, publish the port by uncommenting
- "3001:3001"indocker-compose.yml. - Keep the main port (
3000, the app) on your VPN or private network. - On your subsimail.com account, open the workspace, go to its Tracking domain tab, enter the tracking domain and save. It is signed into the workspace's token, so the next check-in picks it up.
Caddy example
t.yourcompany.com {
reverse_proxy localhost:3001
}
Caddy gets and renews the HTTPS certificate on its own.
nginx example
server {
listen 443 ssl;
server_name t.yourcompany.com;
# ssl_certificate / ssl_certificate_key from certbot
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Same hostname as the app
You don't need a separate domain: the tracking domain can be the same hostname as the app (this is what our own test install does). Send only the tracking paths to port 3001 and everything else to the app:
server {
listen 443 ssl;
server_name mail.yourcompany.com;
# ssl_certificate / ssl_certificate_key from certbot
location = /subsimail-check { proxy_pass http://127.0.0.1:3001; proxy_set_header Host $host; }
location /track/ { proxy_pass http://127.0.0.1:3001; proxy_set_header Host $host; }
location /unsubscribe/ { proxy_pass http://127.0.0.1:3001; proxy_set_header Host $host; }
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
With a separate hostname you can keep the app's own hostname behind a VPN and leave only the tracking one public, which is the stronger setup.
Check my tracking domain
On the same Tracking domain tab, Check my tracking domain makes subsimail.com call https://your-domain/subsimail-check from the internet — the only way to prove what a recipient's mail client will see. It reports Landed, or what to look at: DNS that doesn't resolve yet, a refused connection, a certificate problem, or a server that isn't SubsiMail's tracking port. The check only ever calls that one URL on a public domain and shows nothing about your install.
If the check says 404
“The server answered with HTTP 404 instead of SubsiMail's tracking answer” means the domain reaches a web server, but not SubsiMail's tracking port. Usually the proxy sends /subsimail-check to the app on port 3000, which doesn't serve it, or to another site. Point the domain (or the three tracking paths above) at port 3001 and run the check again. Other results mean: DNS that doesn't resolve yet, a refused connection (port 3001 is not published or is blocked), or a certificate problem.
One tracking domain per client
With workspaces, give each client its own tracking domain. A separate domain per client keeps one client's reputation from touching another's, and the links match each client's brand. All of them can point at the same tracking port.