Infrastructure & DevOps
Complete production reference for VitoCoin's hosting, deployment, monitoring, backup, and security architecture. All configurations documented here are live on production nodes as of 2026-04-09.
00
Live Infrastructure Status
Real-time — auto-refreshes every 20s
● Node 1 — Frankfurt
Vitocoin—
Nginx—
Fail2ban—
Height—
Peers—
Hashrate—
● Node 2 — Moscow
Height—
Peers—
Hashrate—
● Node 3 — Moscow
Height—
Peers—
Hashrate—
Frontend CDN
LIVE
Vercel Edge — vitocoin.com
SSL / HTTPS
ENFORCED
Vercel auto-renew TLS
Nginx Proxy
ACTIVE
Port 80 → 6333, rate-limited
Backups
CRON
Every 6h, 28-file rotation
Fail2ban
ACTIVE
API abuse → 1h ban
Watchdog
5 MIN
systemd timer restarts on failure
Monitor Cron
1 MIN
CPU/RAM/height logged
CI/CD
GITHUB
Push main → Vercel auto-deploy
01
Architecture Diagram
┌─────────────────────────────────────────────────────────────────────────┐
│ USER / BROWSER │
│ https://vitocoin.com │
└────────────────────────────┬────────────────────────────────────────────┘
│ HTTPS (TLS 1.3)
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ VERCEL EDGE NETWORK (CDN) │
│ • Static files: app.html, whitepaper.html, sw.js, manifest.json, … │
│ • Global CDN — <50ms TTFB worldwide │
│ • Auto HTTPS / TLS certificate renewal │
│ • Rewrites: /api/node/* → Node 1 (195.114.193.73:6333) │
│ /api/node2/* → Node 2 (213.139.77.18:6333) │
│ /api/node3/* → Node 3 (84.201.20.90:6333) │
└──────────────┬──────────────────────┬─────────────────┬────────────────┘
│ proxied API calls │ │
▼ ▼ ▼
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐
│ NODE 1 — Frankfurt │ │ NODE 2 — Moscow │ │ NODE 3 — Moscow │
│ 195.114.193.73 │ │ 213.139.77.18 │ │ 84.201.20.90 │
│ Hetzner VPS │ │ Yandex Cloud │ │ Yandex Cloud │
│ ─────────────────── │ │ ─────────────────── │ │ ─────────────────── │
│ Nginx :80 ←→ RL │ │ Nginx :80 ←→ RL │ │ Nginx :80 ←→ RL │
│ ↕ proxy │ │ ↕ proxy │ │ ↕ proxy │
│ vitocoin :6333 API │ │ vitocoin :6333 API │ │ vitocoin :6333 API │
│ vitocoin :6334 P2P │ │ vitocoin :6334 P2P │ │ vitocoin :6334 P2P │
│ Miner: 8 threads │ │ Miner: 4 threads │ │ Miner: 4 threads │
│ SQLite chainstore │ │ SQLite chainstore │ │ SQLite chainstore │
│ ─────────────────── │ │ ─────────────────── │ │ ─────────────────── │
│ Fail2ban (API abuse)│ │ Fail2ban │ │ Fail2ban │
│ UFW (deny default) │ │ UFW │ │ UFW │
│ Watchdog (5min) │ │ Watchdog (5min) │ │ Watchdog (5min) │
│ Monitor cron (1min) │ │ Monitor cron (1min) │ │ Monitor cron (1min) │
│ Backup cron (6h) │ │ Backup cron (6h) │ │ Backup cron (6h) │
└─────────┬────────────┘ └─────────┬────────────┘ └─────────┬────────────┘
│ P2P TCP │ │
└──────────────────────────┴──────────────────────────┘
Full mesh P2P — port 6334
Headers-first sync + block relay
┌─────────────────────────────────────────────────────────────────────────┐
│ SUPABASE (Auth / Wallet metadata) │
│ pjhhurgivuptqeulsqty.supabase.co │
│ • auth.users — email/password JWT auth │
│ • wallets — user_id → VITO address mapping │
│ Direct from frontend (no proxy) — anon key + RLS │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ CI/CD — GitHub + Vercel │
│ Developer pushes to main branch │
│ → GitHub webhook triggers Vercel deployment │
│ → Vercel builds (echo 'static'), deploys static files │
│ → vitocoin.com updated in ~30 seconds │
│ Node updates: SSH push + systemctl restart │
└─────────────────────────────────────────────────────────────────────────┘
02
Hosting & SSL
Frontend — Vercel Edge
| Property | Value |
|---|---|
| Platform | Vercel (Pro) |
| Project | vito-coin-v2 |
| Domain | vitocoin.com (custom, DNS → Vercel) |
| TLS | Auto-provisioned via Let's Encrypt, TLS 1.2/1.3, HSTS enabled |
| CDN | Vercel Edge Network — 100+ PoPs globally, <50ms TTFB |
| Build | echo 'static' — zero build time, pure static delivery |
| Cache | HTML/JS: no-cache; icons: max-age=604800 |
Backend Nodes — VPS
| Node | Provider | Region | Specs | OS |
|---|---|---|---|---|
| Node 1 195.114.193.73 | Hetzner | Frankfurt, DE | 2 vCPU, 4 GB RAM | Ubuntu 22.04 |
| Node 2 213.139.77.18 | Yandex Cloud | Moscow, RU | 4 vCPU, 8 GB RAM | Ubuntu 22.04 |
| Node 3 84.201.20.90 | Yandex Cloud | Moscow, RU | 4 vCPU, 8 GB RAM | Ubuntu 22.04 |
Geographic diversity note: Nodes 2 and 3 share the same datacenter region (Moscow/Yandex). A single regional outage would take 2 of 3 nodes offline simultaneously. Phase 2 expansion targets Frankfurt + New York + Singapore for full geographic redundancy.
03
CI/CD Pipeline
Frontend Deployment (Vercel — automatic)
# Deploy frontend changes: git add -A git commit -m "feat: describe change" git push vercel-deploy HEAD:main --force # → Vercel webhook triggers automatically # → Build runs (echo 'static') in ~5s # → Edge deployment propagates in ~25s # → vitocoin.com updated
Manual Vercel Deploy via API
COMMIT=$(git rev-parse HEAD)
TOKEN="<vercel-token>"
curl -X POST "https://api.vercel.com/v13/deployments?teamId=<team-id>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "vito-coin-v2",
"gitSource": {
"type": "github",
"ref": "main",
"repoId": "1199887899",
"sha": "'"$COMMIT"'"
},
"target": "production"
}'
Node Deployment (SSH push)
# Update all 3 nodes with a new api.py patch: for IP in 195.114.193.73 213.139.77.18 84.201.20.90; do sshpass -p "$PASS" scp patch.py root@$IP:/tmp/patch.py sshpass -p "$PASS" ssh root@$IP "python3 /tmp/patch.py && systemctl restart vitocoin" done # Or via git pull (if node has git access): ssh root@195.114.193.73 "cd /opt/vitocoin && git pull origin main && systemctl restart vitocoin"
Rollback: Each api.py patch creates a
.bak file before modifying. To rollback: cp /opt/vitocoin/vitocoin/api.py.phase2.bak /opt/vitocoin/vitocoin/api.py && systemctl restart vitocoin04
Monitoring
Per-Minute Monitoring Cron
Every minute, /opt/vitocoin/monitor.sh collects and logs:
# Collected fields (JSON per line in /var/log/vitocoin/monitor.log):
{
"ts": "2026-04-09T10:40:00Z", # UTC timestamp
"cpu_pct": 12, # CPU usage %
"ram_pct": 34, # RAM usage %
"disk_pct": 8, # Disk usage %
"height": 11, # Current chain height
"peers": 4, # P2P peer count
"hashrate": "184.81 KH/s", # Miner hashrate
"mining": true # Is miner running?
}
# Read last 60 minutes:
tail -60 /var/log/vitocoin/monitor.log | python3 -c "
import json,sys
for line in sys.stdin:
d=json.loads(line)
print(f'{d[\"ts\"]} cpu={d[\"cpu_pct\"]}% ram={d[\"ram_pct\"]}% h={d[\"height\"]} peers={d[\"peers\"]}')
"
Automated Alerts
- Node unresponsive: If
/statusreturns no valid JSON →systemctl restart vitocoinautomatically - No peers for 2+ minutes: Logged as ALERT in monitor.log (manual investigation required)
- 5-minute watchdog:
vitocoin-watchdog.timer→ callshealthcheck.sh→ restarts node if unhealthy
Prometheus Metrics Endpoint
# Scrape endpoint (Prometheus-compatible text format): curl http://195.114.193.73:6333/metrics # Output sample: # HELP vitocoin_height Current chain height # TYPE vitocoin_height gauge vitocoin_height 11 # HELP vitocoin_peers Connected peer count # TYPE vitocoin_peers gauge vitocoin_peers 4 # HELP vitocoin_chain_work Accumulated chain PoW # TYPE vitocoin_chain_work counter vitocoin_chain_work 47245361163
Log Locations
| Log | Path | Rotation |
|---|---|---|
| Node stdout/stderr | journalctl -u vitocoin | systemd journal, 7 days |
| System monitor | /var/log/vitocoin/monitor.log | Capped at 10,080 lines (7 days) |
| Backup log | /var/log/vitocoin/backup.log | logrotate daily, 14 days |
| Nginx access | /var/log/nginx/access.log | logrotate daily, 14 days |
| Nginx error | /var/log/nginx/error.log | logrotate daily, 14 days |
| Fail2ban | /var/log/fail2ban.log | logrotate weekly |
05
Automated Backups
Blockchain Database Backup
Runs every 6 hours via cron on all 3 nodes. Script: /opt/vitocoin/backup.sh
# Backup process: 1. sqlite3 chainstore.db "PRAGMA wal_checkpoint(TRUNCATE);" # flush WAL first 2. cp chainstore.db /tmp/backup_TIMESTAMP.db 3. gzip /tmp/backup_TIMESTAMP.db 4. mv → /opt/vitocoin/backups/chainstore_YYYYMMDD_HHMMSS.db.gz 5. Prune: keep last 28 backups (7 days × 4/day) # Backup location: /opt/vitocoin/backups/chainstore_20260409_103904.db.gz (4.0K compressed) # To restore from backup: systemctl stop vitocoin gunzip -c /opt/vitocoin/backups/chainstore_TIMESTAMP.db.gz > \ /opt/vitocoin/chaindata/chainstore.db systemctl start vitocoin
Backup Retention Policy
| Frequency | Retention | Count | Storage est. |
|---|---|---|---|
| Every 6 hours | 7 days | 28 files | ~112 KB (at current chain size) |
| Weekly rotation | Manual via cron: find … -mtime +30 -delete | — | Grows with chain |
Recovery SLA: In the event of data loss on one node, the chain can be fully restored from any other running node via P2P sync (automatic on restart) or from a backup file. Current backup RPO: 6 hours maximum.
Cron Schedule (all nodes)
# crontab -l * * * * * /opt/vitocoin/monitor.sh >> /var/log/vitocoin/monitor.log 2>&1 0 */6 * * * /opt/vitocoin/backup.sh >> /var/log/vitocoin/backup.log 2>&1 0 2 * * 0 find /opt/vitocoin/backups -name '*.db.gz' -mtime +30 -delete
06
Performance
Frontend — Target: <2s First Contentful Paint
| Asset | Strategy | Cache | Size |
|---|---|---|---|
| app.html | Static, served by Vercel Edge CDN | no-cache (always fresh) | ~350 KB |
| features-p1/p2.js | Lazy-loaded on demand | no-cache | ~80 KB each |
| Icons (PNG) | Static CDN | max-age=604800 (1 week) | <50 KB |
| Service Worker | PWA offline cache | no-cache on sw.js itself | ~5 KB |
| API calls | Proxied via Vercel to Node 1 | API headers: no-cache | ~1–5 KB/response |
API Performance (Node-side)
- Response time: <10ms for most endpoints at current chain size (11 blocks, 12 UTXOs)
- SSE: 1-second push interval, persistent TCP connection — no polling overhead
- Bottleneck: Python GIL + ThreadingHTTPServer — not suitable for >100 concurrent connections. Nginx worker process limit set to
auto(matches CPU cores).
CDN Headers (vercel.json)
# HTML and JS files — never cached (always fresh): Cache-Control: no-cache, no-store, must-revalidate # Icons — cached aggressively: Cache-Control: public, max-age=604800, immutable # SSE endpoint — disable buffering: Cache-Control: no-cache X-Accel-Buffering: no
07
Security Hardening
Layer 1: Vercel Edge (Frontend)
- HTTPS enforced — no HTTP access to vitocoin.com
- Vercel's global DDoS mitigation active on all edge nodes
- No server-side secrets in frontend code (Supabase anon key is public by design)
- CSP headers: not yet configured (Phase 2 security hardening)
Layer 2: Nginx Rate Limiting (per-node)
# Rate limit zones (nginx.conf): limit_req_zone $binary_remote_addr zone=api_get:10m rate=60r/m; # 1 req/sec avg limit_req_zone $binary_remote_addr zone=api_post:10m rate=10r/m; # 1 req/6sec avg limit_req_zone $binary_remote_addr zone=sse:10m rate=5r/m; # 5 SSE connections/min limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # max concurrent # Burst allowances (nodelay = immediate 429 on burst exceeded): GET endpoints: burst=30 nodelay → 429 Too Many Requests POST endpoints: burst=5 nodelay → 429 SSE endpoint: burst=3 nodelay + max 3 concurrent connections/IP
Layer 3: Fail2ban (API Abuse)
# /etc/fail2ban/jail.d/vitocoin.conf [vitocoin-api] enabled = true maxretry = 20 # 20 rate-limit hits in 60s → ban findtime = 60 bantime = 3600 # 1 hour ban action = iptables-multiport[ports="80,6333"] # View current bans: fail2ban-client status vitocoin-api
Layer 4: UFW Firewall (per-node)
# Current UFW rules (identical on all 3 nodes): Default: deny incoming, allow outgoing ufw allow 22/tcp # SSH (management access) ufw allow 80/tcp # Nginx HTTP (rate-limited API proxy) ufw allow 6334/tcp # P2P port (MUST be open for blockchain sync) # Port 6333 (direct API) is accessible but proxied; can be closed for hardening
Layer 5: Application-Level Miner Protection
# Miner auto-ban in api.py:
if hashrate > 85% of network AND hashrate > 5 MH/s:
_MINER_BAN_LIST.add(ip) # block further requests
# Rate limit in api.py (independent of nginx):
GET: 300 req/min/IP
POST: 60 req/min/IP
# Template requests log miner identity (wallet + hashrate) for audit
08
Firewall Rules
| Port | Protocol | Direction | Action | Purpose |
|---|---|---|---|---|
| 22 | TCP | Inbound | ALLOW | SSH management access |
| 80 | TCP | Inbound | ALLOW | Nginx HTTP proxy (rate-limited) → port 6333 |
| 6333 | TCP | Inbound | ALLOW* | Direct Python API (bypass Nginx) — consider blocking for hardening |
| 6334 | TCP | Inbound | ALLOW | P2P blockchain sync — MUST be open |
| 443 | TCP | Inbound | CLOSED | HTTPS on VPS not configured (SSL handled by Vercel edge only) |
| All others | TCP/UDP | Inbound | DENY | UFW default deny |
*Port 6333 is accessible directly from the internet, bypassing Nginx rate-limiting. To enforce Nginx-only access:
ufw deny 6333/tcp on each node. Vercel proxies all web traffic through port 6333 via the Nginx :80 proxy chain — direct 6333 access is only used for debugging.09
Security Checklist
-
HTTPS enforced on vitocoin.com — Vercel auto-renew Let's Encrypt TLS. HTTP redirected to HTTPS at edge.
-
Nginx rate limiting active on all 3 nodes — 60 GET/min, 10 POST/min per IP. SSE limited to 5 connections/min.
-
Fail2ban active — 20 rate-limit hits in 60s → 1-hour IP ban on ports 80 and 6333.
-
UFW firewall configured — deny all inbound except SSH (22), Nginx proxy (80), P2P (6334).
-
Malicious path blocking in Nginx —
wp-admin,phpmyadmin,.env,.gitreturn 444 (no response). -
Application-level rate limiter in api.py — 300 GET/60 POST per IP per minute. Miner registry with 85% hashrate auto-ban.
-
No secrets in frontend code — Supabase anon key is public by design. Private keys never stored on server.
-
Nginx security headers — X-Frame-Options: DENY, X-Content-Type-Options: nosniff, X-XSS-Protection, Referrer-Policy on all responses.
-
Port 6333 accessible directly (bypasses Nginx) — Low risk currently. Recommended:
ufw deny 6333/tcpto enforce all API traffic through Nginx rate-limiter. Not yet applied to avoid breaking Vercel proxy. -
51% attack risk is high at current hashrate — Network ~900 KH/s; any GPU can exceed this. Disclosed. Risk reduces as external miners join.
-
No CSP (Content Security Policy) headers — Frontend XSS protection not yet configured. Priority Phase 2 item.
-
TODO: SSH key-only auth — Nodes currently use password auth. Recommend: disable PasswordAuthentication in sshd_config, use SSH keys only.
-
TODO: HTTPS on node APIs — Node APIs serve HTTP only. For direct API consumers: consider adding a self-signed cert or Let's Encrypt via certbot + Nginx HTTPS listener on port 443.
-
TODO: Off-site backup replication — Current backups stored on-node only. Recommend: rsync backups to a separate S3 bucket or remote server nightly.
-
TODO: Alert notifications — Monitor alerts currently write to log only. Recommend: integrate with Telegram bot or email for critical alerts (node down, peers=0).