Files
otivm/docs/infrastructure.md
2026-04-25 10:48:33 +00:00

5.5 KiB

OTIVM Infrastructure

Established: April 2026

This document describes the complete infrastructure built for OTIVM. It is the authoritative reference for all incoming assistants and the project owner.


1. Overview

OTIVM runs on a dedicated LXC container (CT 1105) on the TheRON development Proxmox host (srv-a). It is proxied through the WireGuard mesh hub (wg-pk) and served over HTTPS at https://otium.civicus.us.

OTIVM is completely isolated from CIVICVS and TESSERA infrastructure. It shares only the WireGuard mesh and the Nginx proxy node.


2. Network Topology

Browser
  → otium.civicus.us (DNS A record → 198.58.111.109)
  → wg-pk Nginx (HTTPS, SSL termination)
  → WireGuard tunnel
  → otivm-dev (10.110.0.18)
  → Node.js app (port 3000)

3. DNS

Record Type Value
otium.civicus.us A 198.58.111.109

No AAAA record. Traffic is proxied through wg-pk to a container with no public IPv6. Consistent with shell.infra.civicus.us pattern.

DNS is managed in BIND9 on the Linode DNS server. Glue records are at Gandi.


4. Container — CT 1105

Property Value
VMID 1105
Name otivm-dev
Proxmox host srv-a (10.0.0.11)
Template debian-12-standard_12.12-1_amd64
Memory 512MB
Cores 2
Disk 8GB (local-lvm)
LAN IP 10.0.0.23/24
Gateway 10.0.0.1
WireGuard IP 10.110.0.18/32
Unprivileged yes

5. WireGuard

This container is peer 10.110.0.18 on the TheRON WireGuard mesh. The hub is wg-pk (198.58.111.109, mesh address 10.110.0.1).

/etc/wireguard/wg0.conf on otivm-dev

[Interface]
Address = 10.110.0.18/32
ListenPort = 51820
PrivateKey = <stored on node>

[Peer]
PublicKey = 1+Wb++fjXNbY0joOvj4AZvJgF6b125YOPSFsmNqVo3I=
AllowedIPs = 10.110.0.0/22
Endpoint = 198.58.111.109:51820
PersistentKeepalive = 25

Public key

GmJcIZguLxLjh8CNEITp5XUwb1xIDXBYOW/FHj47YUw=

Peer stanza on wg-pk

[Peer]
PublicKey = GmJcIZguLxLjh8CNEITp5XUwb1xIDXBYOW/FHj47YUw=
AllowedIPs = 10.110.0.18/32
Endpoint = 73.36.246.43:51820

Service management

systemctl status wg-quick@wg0
systemctl restart wg-quick@wg0
wg show
ping -c 3 10.110.0.1  # test mesh

6. Nginx on wg-pk

File: /etc/nginx/sites-available/otium.civicus.us

server {
    listen 80;
    listen [::]:80;
    server_name otium.civicus.us;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name otium.civicus.us;

    ssl_certificate /etc/letsencrypt/live/otium.civicus.us/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/otium.civicus.us/privkey.pem;

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        proxy_pass http://10.110.0.18:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

7. SSL Certificate

Property Value
Domain otium.civicus.us
Authenticator --nginx
Certificate path /etc/letsencrypt/live/otium.civicus.us/
Issued April 2026
Expires July 2026
Auto-renewal certbot.timer (systemd, twice daily)

Test renewal: certbot renew --dry-run on wg-pk.

⚠ RULE: Always issue SSL certificates FIRST with --nginx authenticator, then add any basic auth after. Never reverse this order.


8. Application Stack

Component Value
Runtime Node.js v22.22.2
npm 10.9.7
App user otivm
App port 3000
PM2 service pm2-otivm (systemd, enabled)
Python 3.11.2
Python venv /home/otivm/venv
Claude Code v2.1.119

9. Users

User Role
root Container administration only
otivm App user — all app activity, PM2, git, Claude Code

PM2 is always run as otivm. Never as root. Python is always run inside /home/otivm/venv. Never outside.


10. Webmin

Webmin is installed on otivm-dev for file management and container access. It is disabled by default and started manually when needed.

# Aliases in /root/.bashrc
webmin-on   # systemctl start webmin
webmin-off  # systemctl stop webmin

Port 10000. Not exposed beyond the container network. Auto-start is disabled — Webmin is off after every reboot.


11. Gitea

Property Value
Repo https://gitea.barternetwork.us/TheRON/OTIVM
Branch main
Push user otivm@otivm-dev
Clone path /home/otivm/OTIVM
License BSD 2-Clause

Git credentials are stored in /home/otivm/.git-credentials (via credential.helper store).


12. Backup

Baseline backup taken immediately after provisioning, before any code deployed:

/var/lib/vz/dump/vzdump-lxc-1105-2026_04_25-04_10_53.tar.zst

Size: 551MB. Downloaded offline via Webmin.

Backup command:

vzdump 1105 --storage local --compress zstd --mode stop

13. Quick Reference

Check everything is running

# On otivm-dev
systemctl status wg-quick@wg0
ping -c 3 10.110.0.1

# As otivm user
pm2 list

Test the app endpoint

curl -s http://localhost:3000/

Test through the full stack

curl -s https://otium.civicus.us/

docs/infrastructure.md — OTIVM — April 2026