Free series. All open-source. No DevOps background required. Estimated hands-on time: 45–90 minutes.
You have set up a server before. You know what a terminal looks like. You have also watched someone paste a curl command from a random blog post and immediately regret it. This guide is not that. Every command in this part has a stated purpose, a predictable output, and a clean recovery path. If something breaks — and the instructions are written to prevent this — you log into Vultr, click Reinstall, and start fresh in under two minutes.
What makes this part worth your time is not the individual steps — you could figure out each one alone. It is the specific combination of decisions, the order in which they are applied, and the security posture that results. By the end of this article, your server will have zero publicly accessible ports beyond two, an administrative interface that is invisible to port scanners, and five independent security layers verified and operational. That is not a weekend project you abandon. That is a foundation you build on.
Let’s build it.
What You Will Complete in This Part
Five things will be true when this part is done:
- A Vultr VPS running Ubuntu 24.04 LTS — your isolated machine in a global data center, owned entirely by you.
- A custom domain pointing to Cloudflare’s network — the address your team uses to reach every service.
- Cloudflare Zero Trust deployed and active — DDoS mitigation, WAF, and authenticated access control, all at zero cost for up to 50 users.
- Server-level defenses configured — UFW, fail2ban, unattended-upgrades, and hardened sysctl parameters.
- Node.js 24 LTS installed and the OpenClaw foundation ready for Part 3. Five security layers active and verified. The remaining three are completed in Part 3. Read time: ~15 min. Hands-on: ~45–90 min. Prerequisites: Part 1 read. A credit card for Vultr (hourly billing, cancel anytime). An email address you control.
Step 1: Provisioning Your Vultr Server
Vultr is a global cloud provider with DCs across NA, EU, and APAC. You are provisioning a Cloud Compute instance — dedicated vCPU, dedicated RAM, dedicated SSD, isolated from other tenants.
Navigate to vultr.com. Create an account. Vultr charges by the hour and bills monthly. No contract. Destroy the server and billing stops.
Click Deploy → Cloud Compute — Shared CPU.
Select a DC closest to your users (US: ATL/CHI/DAL/LA/MIA/NY/SEA).
Server Image: Ubuntu 24.04 LTS. Canonical commits to security patches through April 2029.
Server Size:
Plan vCPU RAM SSD $/mo Use case
Starter 1 2 GB 55 GB ~$12 Single user / evaluation
Recommended 2 4 GB 80 GB ~$24 3–8 users (used in this guide)
Growth 4 8 GB 160 GB ~$48 8–30 users
Additional Features: enable IPv6 (free, needed for some Part 3 services). Hostname: anything meaningful (visible only in your dashboard).
Root Password: 20+ characters, randomly generated, stored in a password manager. Bitwarden is free and recommended. If you don’t use a password manager yet, start now — you will generate several credentials during this build.
Click Deploy Now. Server provisions in ~60 seconds. Note the IP address — you need it in Step 3.
Step 2: Registering Your Domain
Your domain is the address for every service in the stack:
cloud.yourdomain.com → Nextcloud ai.yourdomain.com → AI proxy remote.yourdomain.com → Guacamole grafana.yourdomain.com → Grafana ssh.yourdomain.com → SSH (tunnel only)
Cloudflare Registrar (cloudflare.com/products/registrar) is recommended — consolidates domain + security in one dashboard. .com domains ~$10.44/year. Other registrars work fine.
Choose something short, professional, easy to say aloud. Complete the registration.
Step 3: Deploying Cloudflare Zero Trust
Cloudflare routes ~20% of global web traffic. The Zero Trust free tier (≤50 users) provides WAF, DDoS mitigation, and Access authentication — capabilities that cost tens of thousands/year commercially.
Account Setup
If you used Cloudflare Registrar, your account exists. Otherwise: dash.cloudflare.com → free account.
Immediately enable 2FA. My Profile → Authentication → Two-Factor Authentication. This is not optional. A compromised Cloudflare account compromises your entire security layer.
If using an external registrar: Add a Site → Free plan → update nameservers to the two Cloudflare provides. Propagation: minutes to 24 hours.
Zero Trust Setup
Click Zero Trust in the left panel. Choose a team name (e.g., mybase). Select the Free plan.
Creating the Tunnel
The Cloudflare Tunnel inverts the conventional model. Instead of opening ports for inbound connections (which creates attack surface), your server initiates an outbound connection to Cloudflare and maintains it. All inbound access routes through this tunnel. Your server’s IP is never directly exposed. Nothing for a port scanner to find.
Zero Trust dashboard → Networks → Tunnels → Create a tunnel → Cloudflared → name it (e.g., mybase-tunnel). Select Debian/Ubuntu. Cloudflare displays a curl command. Copy it.
Open your server console: Vultr dashboard → your server → Console. Log in as root (password won’t display as you type — intentional security behavior). Paste the Cloudflare command. ~30 seconds. Tunnel status shows Healthy.
Tunnel Routing
Public Hostname tab. Add these entries (replace yourdomain.com):
Subdomain Routes to Service
cloud.yourdomain.com http://localhost:8080 Nextcloud
office.yourdomain.com http://localhost:9980 Collabora Online
ai.yourdomain.com http://localhost:8000 AI proxy
remote.yourdomain.com http://localhost:8888 Guacamole
grafana.yourdomain.com http://localhost:3000 Grafana
ssh.yourdomain.com ssh://localhost:50922 SSH admin (tunnel only)
localhost = this server. The port number = which service. Traffic arrives through the tunnel and gets routed to the right process. The service never talks directly to the public internet.
Access Policies
Access → Applications. For each subdomain: Self-hosted Application. Authentication: One-time PIN (email OTP).
Flow: user navigates to cloud.yourdomain.com → Cloudflare intercepts → email prompt → six-digit code sent → code entered → access granted for configurable session duration. No password to manage. No identity provider to configure. The email address is the credential.
Under Include: add authorized email addresses. Changes take effect immediately. Adding a colleague: one email address added to one list.
Step 4: Hardening the Server
Cloudflare is the outer wall. The server needs independent defenses — defense in depth means no single layer’s failure compromises everything.
Commands are executed one at a time. Paste, Enter, wait for prompt, proceed.
Administrative User
Root has unrestricted access. A typo operating as root can cause irreversible damage without confirmation. Create a dedicated admin user:
adduser myadmin
Set a strong 20+ char password (different from root, stored in password manager). Skip the Full Name prompts.
usermod -aG sudo myadmin
myadmin is a placeholder. Use whatever name you prefer throughout.
UFW Firewall
sudo apt update && sudo apt install -y ufw sudo ufw allow 80/tcp comment "HTTP" sudo ufw allow 443/tcp comment "HTTPS" sudo ufw enable
Confirm with y when prompted.
Note what is absent: port 22 is not opened. SSH is routed through the Cloudflare Tunnel — no public SSH port exists. Two ports open. That is the entire external attack surface.
fail2ban
sudo apt install -y fail2ban sudo systemctl enable --now fail2ban
Verify:
sudo systemctl status fail2ban
Expected: active (running).
Automatic Security Updates
sudo apt install -y unattended-upgrades apt-listchanges sudo dpkg-reconfigure -plow unattended-upgrades
Select Yes. Security patches now apply automatically during off-hours.
Kernel Network Hardening
sudo nano /etc/sysctl.d/99-security.conf
Paste:
net.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv4.ip_forward = 0
Save: Ctrl+O → Enter → Ctrl+X. Apply:
sudo sysctl --system
Note on ip_forward = 0: VPN setups require this enabled for packet routing. This architecture uses Cloudflare Tunnel for all external routing — IP forwarding is unnecessary and therefore disabled. Capability not needed is capability that cannot be exploited.
Vultr Hardware Firewall
Vultr dashboard → your server → Firewall. Create a firewall group:
Accept TCP 80 from any Accept TCP 443 from any Drop all other inbound
Apply to your server. You now have two independent firewalls enforcing the same two-port restriction: Vultr hardware + Ubuntu UFW. Both fronted by Cloudflare authentication.
Step 5: Node.js Foundation
OpenClaw (Part 3) runs on Node.js. Install now to avoid a dependency gap:
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - sudo apt install -y nodejs node --version
Expected output: v24.x.x. If error, re-run the first two commands.
Verifying Your Security Stack
Five of eight layers active. Verify:
sudo ufw status verbose
Expected: active, ports 80 + 443 only.
sudo systemctl status fail2ban
Expected: active (running).
sudo systemctl status cloudflared
Expected: active (running).
node --version
Expected: v24.x.x.
If any check fails: re-run the relevant step. Most failures are a missed command or typo. If unresolvable, Vultr Reinstall → clean Ubuntu → restart from Step 4. Cloudflare config (Steps 2–3) is stored independently and doesn’t need redoing.
The Security Posture You Have Built
From the public internet: two open TCP ports (80/443), dual-firewalled (Vultr HW + UFW), both fronted by Cloudflare WAF + DDoS mitigation.
SSH: no public port. Routed through Cloudflare Tunnel, accessible only after email OTP authentication.
fail2ban: monitoring auth logs, auto-blocking repeated failures. unattended-upgrades: patching known CVEs during off-hours. Kernel hardening: active.
This is not security bolted on after the fact. It is the foundation. Every application installed in Parts 3 and 4 inherits this posture. No application gets a public port. No admin interface is directly internet-accessible. Every access path routes through the authenticated tunnel.
A Note on OpenClaw and CVE-2026-25253
Part 1 addressed the vulnerability (CVSS 8.8, High) and the ClawJacked class in detail. The security posture built in this part is precisely what neutralizes them.
The exploit requires an accessible WebSocket endpoint. Your server has no publicly accessible ports beyond 80/443, both behind Cloudflare Access. OpenClaw, when installed in Part 3, will bind to localhost and be accessible only through the authenticated tunnel. No credentials → no access → no exploit.
Patch: OpenClaw 2026.1.29. Specified throughout this guide.
What Part 3 Builds
The foundation is complete. Part 3 installs the intelligence:
Nextcloud — private file sync replacing Google Drive/Dropbox.
Collabora Online — browser-based collaborative editing.
Four-AI unified proxy — ChatGPT + Claude + Gemini + Perplexity through one authenticated interface. API keys never leave the server.
OpenClaw — agentic AI butler with systemd sandboxing, API key isolation, and messaging integrations.
When Part 3 is complete, the system is operational for daily use.
Series: Building Your Private AI Infrastructure
Part What It Covers
Part 1 — Architecture Overview Stack, costs, security model, daily usage
Part 2 — Zero-Trust Server (you are here) Vultr, Cloudflare, UFW, fail2ban, Node.js
Part 3 — The Intelligence Layer Docker, Nextcloud, Collabora, AI proxy, OpenClaw
Part 4 — Operations & Monitoring Guacamole, Prometheus, Grafana, encrypted backups
Part 5 — The Operations Manual Maintenance, audits, cost optimization, runbook
All five parts are published and free. No paywall, no signup, no follow-up sequence.
Legal Disclaimer
The information provided in this series is for educational and informational purposes only. It does not constitute legal, financial, tax, accounting, cybersecurity, or professional advice of any kind. No professional relationship is formed by reading or acting on this content.
All use of techniques, software, services, configurations, or commands described in this series is undertaken at the sole risk of the user. To the maximum extent permitted by applicable law, the author disclaims all liability for any damages arising from use of or reliance upon this content.
This disclaimer is enforceable to the fullest extent permitted by applicable law, including the laws of the State of California (Cal. Civ. Code §§1668, 3513) and the State of New York (N.Y. GOL §5-323), and applicable federal law. References to all third-party products are for informational purposes only. The author has no commercial relationship with any provider mentioned.
Part 3 is next. Questions, errors, or environment-specific issues belong in the comments. Every one gets read. The technical ones get detailed answers.
— Kusunoki International Tax Specialist & Systems Builder Sapporo, Japan | @kusunoki---
title: "I Built a Zero-Trust Server With Only 2 Open Ports — Building Your Private AI Infrastructure [2/5]"
published: true
tags: linux, security, selfhosted, tutorial
series: Building Your Private AI Infrastructure
Free series. All open-source. No DevOps background required. Estimated hands-on time: 45–90 minutes.
You have set up a server before. You know what a terminal looks like. You have also watched someone paste a curl command from a random blog post and immediately regret it. This guide is not that. Every command in this part has a stated purpose, a predictable output, and a clean recovery path. If something breaks — and the instructions are written to prevent this — you log into Vultr, click Reinstall, and start fresh in under two minutes.
What makes this part worth your time is not the individual steps — you could figure out each one alone. It is the specific combination of decisions, the order in which they are applied, and the security posture that results. By the end of this article, your server will have zero publicly accessible ports beyond two, an administrative interface that is invisible to port scanners, and five independent security layers verified and operational. That is not a weekend project you abandon. That is a foundation you build on.
Let's build it.
What You Will Complete in This Part
Five things will be true when this part is done:
1. A Vultr VPS running Ubuntu 24.04 LTS — your isolated machine in a global data center, owned entirely by you.
2. A custom domain pointing to Cloudflare's network — the address your team uses to reach every service.
3. Cloudflare Zero Trust deployed and active — DDoS mitigation, WAF, and authenticated access control, all at zero cost for up to 50 users.
4. Server-level defenses configured — UFW, fail2ban, unattended-upgrades, and hardened sysctl parameters.
5. Node.js 24 LTS installed and the OpenClaw foundation ready for Part 3.
Five security layers active and verified. The remaining three are completed in Part 3.
Read time: ~15 min. Hands-on: ~45–90 min. Prerequisites: Part 1 read. A credit card for Vultr (hourly billing, cancel anytime). An email address you control.
Step 1: Provisioning Your Vultr Server
Vultr is a global cloud provider with DCs across NA, EU, and APAC. You are provisioning a Cloud Compute instance — dedicated vCPU, dedicated RAM, dedicated SSD, isolated from other tenants.
Navigate to vultr.com. Create an account. Vultr charges by the hour and bills monthly. No contract. Destroy the server and billing stops.
Click Deploy → Cloud Compute — Shared CPU.
Select a DC closest to your users (US: ATL/CHI/DAL/LA/MIA/NY/SEA).
Server Image: Ubuntu 24.04 LTS. Canonical commits to security patches through April 2029.
Server Size:
| Plan | vCPU | RAM | SSD | $/mo | Use case |
|---|---|---|---|---|---|
| Starter | 1 | 2 GB | 55 GB | ~$12 | Single user / evaluation |
| Recommended | 2 | 4 GB | 80 GB | ~$24 | 3–8 users (used in this guide) |
| Growth | 4 | 8 GB | 160 GB | ~$48 | 8–30 users |
Additional Features: enable IPv6 (free, needed for some Part 3 services). Hostname: anything meaningful (visible only in your dashboard).
Root Password: 20+ characters, randomly generated, stored in a password manager. Bitwarden is free and recommended. If you don't use a password manager yet, start now — you will generate several credentials during this build.
Click Deploy Now. Server provisions in ~60 seconds. Note the IP address — you need it in Step 3.
Step 2: Registering Your Domain
Your domain is the address for every service in the stack:
cloud.yourdomain.com → Nextcloud
ai.yourdomain.com → AI proxy
remote.yourdomain.com → Guacamole
grafana.yourdomain.com → Grafana
ssh.yourdomain.com → SSH (tunnel only)
Cloudflare Registrar (cloudflare.com/products/registrar) is recommended — consolidates domain + security in one dashboard. .com domains ~$10.44/year. Other registrars work fine.
Choose something short, professional, easy to say aloud. Complete the registration.
Step 3: Deploying Cloudflare Zero Trust
Cloudflare routes ~20% of global web traffic. The Zero Trust free tier (≤50 users) provides WAF, DDoS mitigation, and Access authentication — capabilities that cost tens of thousands/year commercially.
Account Setup
If you used Cloudflare Registrar, your account exists. Otherwise: dash.cloudflare.com → free account.
Immediately enable 2FA. My Profile → Authentication → Two-Factor Authentication. This is not optional. A compromised Cloudflare account compromises your entire security layer.
If using an external registrar: Add a Site → Free plan → update nameservers to the two Cloudflare provides. Propagation: minutes to 24 hours.
Zero Trust Setup
Click Zero Trust in the left panel. Choose a team name (e.g., mybase). Select the Free plan.
Creating the Tunnel
The Cloudflare Tunnel inverts the conventional model. Instead of opening ports for inbound connections (which creates attack surface), your server initiates an outbound connection to Cloudflare and maintains it. All inbound access routes through this tunnel. Your server's IP is never directly exposed. Nothing for a port scanner to find.
Zero Trust dashboard → Networks → Tunnels → Create a tunnel → Cloudflared → name it (e.g., mybase-tunnel). Select Debian/Ubuntu. Cloudflare displays a curl command. Copy it.
Open your server console: Vultr dashboard → your server → Console. Log in as root (password won't display as you type — intentional security behavior). Paste the Cloudflare command. ~30 seconds. Tunnel status shows Healthy.
Tunnel Routing
Public Hostname tab. Add these entries (replace yourdomain.com):
| Subdomain | Routes to | Service |
|---|---|---|
| cloud.yourdomain.com | http://localhost:8080 | Nextcloud |
| office.yourdomain.com | http://localhost:9980 | Collabora Online |
| ai.yourdomain.com | http://localhost:8000 | AI proxy |
| remote.yourdomain.com | http://localhost:8888 | Guacamole |
| grafana.yourdomain.com | http://localhost:3000 | Grafana |
| ssh.yourdomain.com | ssh://localhost:50922 | SSH admin (tunnel only) |
localhost = this server. The port number = which service. Traffic arrives through the tunnel and gets routed to the right process. The service never talks directly to the public internet.
Access Policies
Access → Applications. For each subdomain: Self-hosted Application. Authentication: One-time PIN (email OTP).
Flow: user navigates to cloud.yourdomain.com → Cloudflare intercepts → email prompt → six-digit code sent → code entered → access granted for configurable session duration. No password to manage. No identity provider to configure. The email address is the credential.
Under Include: add authorized email addresses. Changes take effect immediately. Adding a colleague: one email address added to one list.
Step 4: Hardening the Server
Cloudflare is the outer wall. The server needs independent defenses — defense in depth means no single layer's failure compromises everything.
Commands are executed one at a time. Paste, Enter, wait for prompt, proceed.
Administrative User
Root has unrestricted access. A typo operating as root can cause irreversible damage without confirmation. Create a dedicated admin user:
adduser myadmin
Set a strong 20+ char password (different from root, stored in password manager). Skip the Full Name prompts.
usermod -aG sudo myadmin
myadmin is a placeholder. Use whatever name you prefer throughout.
UFW Firewall
sudo apt update && sudo apt install -y ufw
sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"
sudo ufw enable
Confirm with y when prompted.
Note what is absent: port 22 is not opened. SSH is routed through the Cloudflare Tunnel — no public SSH port exists. Two ports open. That is the entire external attack surface.
fail2ban
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
Verify:
sudo systemctl status fail2ban
Expected: active (running).
Automatic Security Updates
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
Select Yes. Security patches now apply automatically during off-hours.
Kernel Network Hardening
sudo nano /etc/sysctl.d/99-security.conf
Paste:
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.ip_forward = 0
Save: Ctrl+O → Enter → Ctrl+X. Apply:
sudo sysctl --system
Note on ip_forward = 0: VPN setups require this enabled for packet routing. This architecture uses Cloudflare Tunnel for all external routing — IP forwarding is unnecessary and therefore disabled. Capability not needed is capability that cannot be exploited.
Vultr Hardware Firewall
Vultr dashboard → your server → Firewall. Create a firewall group:
Accept TCP 80 from any
Accept TCP 443 from any
Drop all other inbound
Apply to your server. You now have two independent firewalls enforcing the same two-port restriction: Vultr hardware + Ubuntu UFW. Both fronted by Cloudflare authentication.
Step 5: Node.js Foundation
OpenClaw (Part 3) runs on Node.js. Install now to avoid a dependency gap:
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version
Expected output: v24.x.x. If error, re-run the first two commands.
Verifying Your Security Stack
Five of eight layers active. Verify:
sudo ufw status verbose
Expected: active, ports 80 + 443 only.
sudo systemctl status fail2ban
Expected: active (running).
sudo systemctl status cloudflared
Expected: active (running).
node --version
Expected: v24.x.x.
If any check fails: re-run the relevant step. Most failures are a missed command or typo. If unresolvable, Vultr Reinstall → clean Ubuntu → restart from Step 4. Cloudflare config (Steps 2–3) is stored independently and doesn't need redoing.
The Security Posture You Have Built
From the public internet: two open TCP ports (80/443), dual-firewalled (Vultr HW + UFW), both fronted by Cloudflare WAF + DDoS mitigation.
SSH: no public port. Routed through Cloudflare Tunnel, accessible only after email OTP authentication.
fail2ban: monitoring auth logs, auto-blocking repeated failures. unattended-upgrades: patching known CVEs during off-hours. Kernel hardening: active.
This is not security bolted on after the fact. It is the foundation. Every application installed in Parts 3 and 4 inherits this posture. No application gets a public port. No admin interface is directly internet-accessible. Every access path routes through the authenticated tunnel.
A Note on OpenClaw and CVE-2026-25253
Part 1 addressed the vulnerability (CVSS 8.8, High) and the ClawJacked class in detail. The security posture built in this part is precisely what neutralizes them.
The exploit requires an accessible WebSocket endpoint. Your server has no publicly accessible ports beyond 80/443, both behind Cloudflare Access. OpenClaw, when installed in Part 3, will bind to localhost and be accessible only through the authenticated tunnel. No credentials → no access → no exploit.
Patch: OpenClaw 2026.1.29. Specified throughout this guide.
What Part 3 Builds
The foundation is complete. Part 3 installs the intelligence:
Nextcloud — private file sync replacing Google Drive/Dropbox.
Collabora Online — browser-based collaborative editing.
Four-AI unified proxy — ChatGPT + Claude + Gemini + Perplexity through one authenticated interface. API keys never leave the server.
OpenClaw — agentic AI butler with systemd sandboxing, API key isolation, and messaging integrations.
When Part 3 is complete, the system is operational for daily use.
Series: Building Your Private AI Infrastructure
| Part | What It Covers |
|---|---|
| Part 1 — Architecture Overview | Stack, costs, security model, daily usage |
| Part 2 — Zero-Trust Server (you are here) | Vultr, Cloudflare, UFW, fail2ban, Node.js |
| Part 3 — The Intelligence Layer | Docker, Nextcloud, Collabora, AI proxy, OpenClaw |
| Part 4 — Operations & Monitoring | Guacamole, Prometheus, Grafana, encrypted backups |
| Part 5 — The Operations Manual | Maintenance, audits, cost optimization, runbook |
All five parts are published and free. No paywall, no signup, no follow-up sequence.
Legal Disclaimer
The information provided in this series is for educational and informational purposes only. It does not constitute legal, financial, tax, accounting, cybersecurity, or professional advice. All use is at the sole risk of the user. To the maximum extent permitted by applicable law, including the laws of the State of California (Cal. Civ. Code §§1668, 3513) and the State of New York (N.Y. GOL §5-323), the author disclaims all liability for any damages arising from use of this content. References to all third-party products are for informational purposes only. The author has no commercial relationship with any provider mentioned.
Part 3 is next. Questions, errors, or environment-specific issues belong in the comments. Every one gets read. The technical ones get detailed answers.
— Kusunoki
International Tax Specialist & Systems Builder
Sapporo, Japan | @kusunoki
Top comments (0)