VPS & Services
server1.series-x.ai (66.29.139.128). Ubuntu, nginx 1.24, 8 cores, 11 GB RAM, 237 GB disk.
Node 22, Python 3.11. Backups nightly 03:30 UTC.
Public services
| Host |
Port |
Service |
| crm.series-x.ai |
443 |
CRM portal (nginx → static + edge functions) |
| agentx.series-x.ai |
443 |
Open WebUI |
| agent.series-x.ai |
443 |
Hermes dashboard |
| proposals.series-x.ai |
443 |
Client proposals (basic auth realms) |
| missioncontrol.series-x.ai |
443 |
Mission Control colony (basic auth) |
| docs.series-x.ai |
443 |
This documentation site |
Internal services (127.0.0.1)
| Port |
Service |
Purpose |
| 8793 |
crm-madnion-sso |
CRM session bridge (login, /auth/session, validate) |
| 8798 |
crm-api |
Legacy CRM API (being replaced by Supabase edge) |
| 8794 |
paysched |
Payment schedules |
| 8796 |
push-stripe |
Stripe checkout links |
| 8800 |
video-api |
Remotion render API |
| 8791 |
signbee |
E-signing webhooks |
| 5274 |
missioncontrol |
Colony server |
| 9910 |
hermes-gateway |
WhatsApp bridge |
Nightly jobs
| Time (UTC) |
Job |
| 03:30 |
VPS backup |
| 06:15 |
/root/crm-refresh/run_daily.sh: Stripe pull → build tables → Supabase dataset sync → persist cashflow/subscriptions → Wise pull |
Deployment patterns
- Static pages: rsync to
/var/www/<site>/, nginx serves.
- Node services: code in
/opt/<service>/, systemd unit in /etc/systemd/system/,
secrets via EnvironmentFile (never in code or repo). systemctl restart <service>.
- Nginx changes: back up vhost → edit →
nginx -t → systemctl reload nginx.
- Repo-first: CRM code lives in
github.com/series-a-uk/series-x-crm; working copy
/root/crm-repo. Commit before/after deploys.
TLS
certbot per-subdomain (/etc/letsencrypt/live/<host>/). New subdomain: create vhost with
.well-known/acme-challenge root /var/www/certbot, obtain cert, reload.
Known failure classes
crm-api wedged Postgres client → systemctl restart crm-api (fixes it every time).
- Supabase direct DB host unreachable over IPv6 → always use the
aws-1-eu-west-1.pooler.supabase.com:6543 pooler.
- Taplio re-sync resurrects deleted calendar posts → delete twice, verify by body-text match.