Estimated hands-on time: 45–90 minutes.
Laying the Foundation: Vultr, Ubuntu, and Zero-Trust in an Afternoon
Building Your Private AI Infrastructure [Part 2 of 5]
Free series. All open-source. No DevOps background required. Estimated hands-on time: 45–90 minutes.
The Black Screen Problem
Every guide that involves a terminal loses a third of its readers at the first command prompt.
That is a failure of explanation, not a limitation of the reader.
This part of the series will ask you to type commands into a terminal — a text interface that looks, to the uninitiated, like something from a 1983 film about hackers. There are no icons. There is no undo button. The cursor blinks and waits.
Here is what you actually need to know: every command in this guide has been tested, has a stated purpose, and produces a specific, observable result. If something goes wrong — and the instructions are designed to prevent this — you log into your Vultr dashboard, click Reinstall, and the server returns to a clean state in under two minutes. Nothing on your laptop is affected. Nothing on your laptop was ever at risk.
The terminal is not a trap. It is a precise tool, and precision is exactly what you need when you are building infrastructure that will protect your business data.
Let's build it.
What You Will Complete in This Part
By the end of this article, five things will be true.
You will have a Vultr virtual private server running Ubuntu 24.04 LTS — your private, isolated machine in a global data center, accessible from any browser, owned entirely by you.
You will have a custom domain name pointing to Cloudflare's network — the address your team will use to reach every service you build.
You will have Cloudflare Zero Trust deployed and active — the outermost security layer, providing DDoS mitigation, web application firewall protection, and authenticated access control, all at no cost for up to 50 users.
You will have your server's internal defenses configured — UFW firewall, fail2ban intrusion prevention, automatic security updates, and hardened kernel network settings.
You will have Node.js installed and the foundation for OpenClaw — your agentic AI butler — ready for Part 3.
When this part is complete, your server will have zero publicly accessible ports beyond the two required for web traffic, an administrative interface that is invisible to the public internet, and five independent security layers active and verified. The sixth, seventh, and eighth layers are completed in Part 3.
Read time: approximately 15 minutes.
Hands-on time: approximately 45 to 90 minutes, depending on your pace.
Prerequisites: Part 1 read and understood. A credit card for Vultr (billed monthly, cancel anytime). An email address you control.
Step 1: Provisioning Your Vultr Server
Vultr is a global cloud infrastructure provider with data centers across North America, Europe, and Asia-Pacific. You are renting a virtual private server — an isolated virtual machine on shared physical hardware, with dedicated RAM, dedicated SSD storage, and no resource contention from other tenants. Think of it as a private apartment in a large building: your own walls, your own keys, your own rules. No one else on the same physical hardware can access your data or affect your performance.
Navigate to vultr.com and create an account. You will need an email address and a payment method. Vultr charges by the hour and bills monthly. There is no contract. You can destroy the server and stop billing at any time.
Once your account is created, click "Deploy" and select "Cloud Compute — Shared CPU."
Choose your server location. For a US-based business, select a data center in Atlanta, Chicago, Dallas, Los Angeles, Miami, New York, or Seattle — whichever is geographically closest to your primary users. Proximity to the data center reduces latency for everyday operations.
Under "Server Image," select Ubuntu 24.04 LTS. This is the Long Term Support release — meaning Canonical, Ubuntu's developer, commits to security patches and updates through April 2029. LTS releases are the correct choice for production infrastructure: they are stable, well-documented, and maintained on a predictable schedule.
Under "Server Size," select your plan based on the guidance from Part 1. The 2 vCPU / 4 GB RAM / 80 GB SSD plan at approximately $24/month is the recommended configuration for three to eight users with the full stack running. The 1 vCPU / 2 GB RAM / 55 GB SSD plan at approximately $12/month is sufficient for a single user evaluating the system. The 4 vCPU / 8 GB RAM / 160 GB SSD plan at approximately $48/month serves eight to thirty users under normal business workloads.
Under "Additional Features," enable "IPv6" — it costs nothing and will be relevant for some services in Part 3.
Under "Server Hostname," enter something meaningful to you: your business name, a project name, or simply "myserver." This is only visible in your Vultr dashboard.
Under "Root Password," you will set the master credential for your server. This is the equivalent of a master key that opens every door simultaneously. Use a randomly generated password of at least 20 characters — a mix of uppercase letters, lowercase letters, numbers, and symbols. Something like Kx9mP2wL@vN7qR5jT! in structure, with your own random characters. Do not use your name, your business name, a dictionary word, a date, or any variation of "password."
Write this password down and store it in a password manager. Bitwarden is free, open-source, and recommended. If you do not yet use a password manager, this is the moment to start one — you will generate several strong credentials during this build, and a password manager is the only sane way to manage them.
Click "Deploy Now." Your server will be provisioned within 60 seconds. When its status shows "Running," your private infrastructure exists. Note the IP address displayed in your dashboard — you will need it in Step 3.
Step 2: Registering Your Domain
A domain name is the address your team will use to reach every service in this stack. Without one, your services are reachable only by IP address — a string of numbers that is unmemorable, difficult to secure with HTTPS, and unsuitable for professional use.
With a domain, your private cloud becomes cloud.yourdomain.com. Your AI portal becomes ai.yourdomain.com. Your remote desktop becomes remote.yourdomain.com. Your monitoring dashboard becomes grafana.yourdomain.com. Every service has a clear, memorable address that you control.
Navigate to Cloudflare's domain registrar at cloudflare.com/products/registrar. Cloudflare Registrar is recommended here specifically because it simplifies the DNS configuration in this step — your domain and your security layer will be managed in the same dashboard, which eliminates one potential point of error. .com domains run approximately $10.44 per year at Cloudflare's cost-plus pricing. Other registrars work equally well if you prefer one you already use.
Search for your preferred domain name. Choose something short, professional, and easy to communicate verbally — you will be typing it into terminal commands and reading it aloud to colleagues. If your first choice is taken, have three or four alternatives ready.
Complete the registration. You will use this domain throughout Parts 2 through 5.
Step 3: Deploying Cloudflare Zero Trust
Cloudflare is one of the largest internet infrastructure networks in the world, routing approximately 20% of global web traffic through its systems. The Zero Trust free tier — available to organizations with up to 50 users — provides enterprise-grade capabilities that would cost tens of thousands of dollars per year to license from commercial security vendors.
What you are deploying in this step is the outermost layer of your security architecture: a web application firewall and DDoS mitigation system that filters all inbound traffic before it reaches your server's IP address, and an access control layer that authenticates every user before any request is forwarded to any service.
Creating Your Cloudflare Account
If you registered your domain through Cloudflare Registrar in Step 2, your account already exists. If you used another registrar, navigate to dash.cloudflare.com and create a free account.
The first thing you will do after logging in is enable two-factor authentication. Navigate to My Profile, then Authentication, then Two-Factor Authentication. Install Google Authenticator or Authy on your phone — both are free — and follow the setup flow. This is not optional. If your Cloudflare account is compromised, an attacker can modify the security layer protecting your entire stack. Two-factor authentication is the single most effective step you can take to prevent that.
If you used a registrar other than Cloudflare, add your domain to Cloudflare now: click "Add a Site," enter your domain name, select the Free plan, and follow the prompts. Cloudflare will display two nameserver addresses — for example, ada.ns.cloudflare.com and ben.ns.cloudflare.com. Log into your registrar's control panel and update your domain's nameserver records to these two addresses. Propagation takes between a few minutes and 24 hours. Cloudflare's dashboard will show "Active" when the change has propagated.
Setting Up Zero Trust
In your Cloudflare dashboard, click "Zero Trust" in the left navigation panel. Choose a team name — a short alphanumeric identifier, such as your business name or a project name, for example mybase. Select the Free plan. Complete the setup flow.
Creating the Tunnel
The Cloudflare Tunnel is the architectural element that makes this security model possible. Rather than opening ports on your server for incoming connections — which creates attack surface — the tunnel works in reverse: your server initiates an outbound connection to Cloudflare's network and maintains it. All inbound access to your services routes through this tunnel. Your server's IP address is never directly exposed. There is nothing for a port scanner to find.
In the Zero Trust dashboard, navigate to Networks, then Tunnels. Click "Create a tunnel," select "Cloudflared," and name your tunnel — for example, mybase-tunnel. On the next screen, select "Debian/Ubuntu" as the operating system. Cloudflare will display a single command — a long string beginning with curl. Copy this entire command.
Now open your server's console. In your Vultr dashboard, click on your server, then click "Console." A terminal window will open in your browser. This is a direct connection to your server's command line.
You will see a login prompt. Type root and press Enter. Type your root password and press Enter. The password field will show nothing as you type — this is intentional security behavior, not a malfunction. The characters are being recorded; they are simply not displayed.
Once you are logged in, paste the command you copied from Cloudflare and press Enter. The installation will take approximately 30 seconds. When it completes, return to the Cloudflare dashboard. The tunnel status will show "Healthy." Your server and Cloudflare are now connected through an encrypted, authenticated channel that runs entirely from your server outward. No inbound ports required. Nothing to scan from outside.
Configuring Tunnel Routing
The tunnel is a conduit. You now need to tell it where to route traffic for each subdomain. In the Cloudflare tunnel configuration, click the "Public Hostname" tab and add the following entries. Replace yourdomain.com with your actual domain name throughout.
cloud.yourdomain.com routes to http://localhost:8080 — this will be Nextcloud, your private file sync and sharing service.
office.yourdomain.com routes to http://localhost:9980 — this will be Collabora Online, your collaborative document editing environment.
ai.yourdomain.com routes to http://localhost:8000 — this will be your unified AI proxy, the single interface for all four AI assistants.
remote.yourdomain.com routes to http://localhost:8888 — this will be Apache Guacamole, your browser-based remote desktop gateway.
grafana.yourdomain.com routes to http://localhost:3000 — this will be your Grafana monitoring dashboard.
ssh.yourdomain.com routes to ssh://localhost:50922 — this is the SSH access point for server administration, routed through the authenticated tunnel rather than exposed on the public internet.
The term localhost in each entry means "this server itself." The number following the colon is the port — think of it as a room number within the server. Traffic arriving through the tunnel for cloud.yourdomain.com will be directed to port 8080 on the server's internal interface, where Nextcloud will be listening. The service never communicates directly with the public internet. The tunnel handles all external communication.
Configuring Access Policies
The tunnel controls routing. Access policies control who is permitted to initiate a session through the tunnel.
In the Zero Trust dashboard, navigate to Access, then Applications. For each subdomain listed above except any public-facing website, create a Self-hosted Application. Set the domain to the corresponding subdomain. Under Authentication, select "One-time PIN" as the identity provider.
The one-time PIN method works as follows: when a user navigates to cloud.yourdomain.com in a browser, Cloudflare intercepts the request and presents an authentication screen. The user enters their email address. Cloudflare sends a six-digit code to that address. The user enters the code. If the email address is in the policy's allowed list, access is granted for a configurable session duration. No password to manage, no separate identity provider to configure, no user account to create. The user's email address is the credential.
Under "Include" in the policy rule, add the email addresses of everyone who should have access to that service. You can add and remove addresses at any time from the dashboard. Changes take effect immediately.
For services that should be accessible only to you — the server's SSH gateway, for example — restrict the policy to your email address alone.
To grant a colleague access to your private cloud: add their email address to the cloud.yourdomain.com policy. They navigate to the URL, enter their email address, receive a six-digit code, enter it, and they are in. No VPN client installation. No shared password. No user account provisioning beyond adding an email to a list.
Step 4: Hardening the Server
Cloudflare is the outer wall. The server itself needs independent defenses — not because Cloudflare will fail, but because defense in depth means no single layer's failure compromises the whole.
The following commands are executed in the server console, one by one. Each has a stated purpose. Each produces a verifiable result. Paste each command, press Enter, wait for it to complete, then proceed to the next.
Creating an Administrative User
The root account is the server's master key. It has unrestricted access to every file and every command. Operating as root for daily administration means that a typo — deleting a file with a slightly malformed command, for example — can cause irreversible damage without a confirmation prompt.
Create a dedicated administrative user for daily work and reserve the root credential for initial setup only.
adduser myadmin
You will be prompted for a password. Use a strong, randomly generated password of at least 20 characters — different from your root password and stored in your password manager. The prompts for Full Name, Room Number, and similar fields can be left blank by pressing Enter.
Grant this user administrative privileges:
usermod -aG sudo myadmin
The name myadmin is a placeholder. Replace it with any name you prefer. If you change it here, use your chosen name wherever myadmin appears in subsequent commands throughout this guide.
Configuring the UFW Firewall
UFW — Uncomplicated Firewall — is Ubuntu's built-in firewall manager. You are configuring it to allow inbound connections on port 80 (HTTP) and port 443 (HTTPS) only. Every other port will be blocked.
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
When prompted to confirm enabling the firewall, type y and press Enter.
Note what is absent from this configuration: port 22 for SSH is not opened. In a conventional server setup, SSH on port 22 is the administrative entry point — and one of the most frequently probed ports on the internet. In this architecture, SSH administration is routed through the Cloudflare Tunnel configured in Step 3, which means the administrative interface is not visible to the public internet at any port. There is nothing to probe. This is a fundamental architectural advantage over VPN-based setups, where the VPN port must be exposed.
Two ports open. That is the entire external attack surface.
Installing fail2ban
fail2ban monitors your server's authentication logs and automatically blocks IP addresses that generate repeated failed login attempts. It is an autonomous intrusion prevention system that operates continuously without requiring attention.
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
Those two commands install fail2ban, configure it to start automatically when the server boots, and start it immediately. It is now running. If any automated script or human attacker attempts to brute-force any authentication endpoint on your server, fail2ban will detect the pattern and block the source IP before the attempt can succeed.
To confirm it is running:
sudo systemctl status fail2ban
The output should show "active (running)" in green. If it does not, run the enable command again and check for error output.
Enabling Automatic Security Updates
Software vulnerabilities are discovered continuously. Patches are released continuously. Manually applying security updates to a production server every day is not a realistic operational model for a small business.
The unattended-upgrades package configures Ubuntu to download and apply security patches automatically — specifically security patches, not general software updates, which can occasionally introduce breaking changes. Security patches are applied without human intervention. The distinction matters: you are automating the application of fixes for known vulnerabilities, not automatically upgrading application versions.
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
A dialog will appear asking whether to enable automatic updates. Select "Yes." The system will now apply security patches during off-hours without requiring you to log in, check for updates, or schedule maintenance windows.
Hardening Kernel Network Settings
The Linux kernel's network stack has configurable parameters that control how it responds to certain classes of potentially malicious network traffic. The following settings disable IP redirect acceptance, source routing, and SYN flood amplification — attack vectors that are rarely relevant to legitimate traffic but frequently exploited in network-layer attacks.
Open the configuration file:
sudo nano /etc/sysctl.d/99-security.conf
The nano text editor will open. Paste the following block exactly as written:
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
To save the file: press Ctrl and O simultaneously, then press Enter to confirm the filename. To exit nano: press Ctrl and X simultaneously.
Apply the settings immediately:
sudo sysctl --system
A note on the last line, ip_forward = 0: in a VPN-based server configuration, IP forwarding must be enabled — set to 1 — so that the VPN server can route packets between the tunnel and the network. In this architecture, Cloudflare Tunnel handles all external routing and requires only an outbound connection from the server. IP forwarding on the server itself is unnecessary and is therefore disabled. Disabling unnecessary kernel features is a basic security principle: capability not needed is capability that cannot be exploited.
Configuring the Vultr Hardware Firewall
In addition to UFW operating at the Ubuntu software level, Vultr provides a hardware-level firewall that filters traffic before it reaches your server's operating system at all. This is an independent enforcement of the same port restrictions — a second barrier that holds even if the software firewall has a configuration error.
In your Vultr dashboard, navigate to your server's detail page, then to "Firewall." Create a new firewall group with the following rules:
Accept inbound TCP on port 80 from any source.
Accept inbound TCP on port 443 from any source.
Drop all other inbound traffic.
Apply this firewall group to your server.
Your server now has two independent firewalls enforcing the same two-port restriction: the Vultr hardware firewall at the infrastructure layer and UFW at the operating system layer. An attacker scanning your server's IP address will find two open ports, both of which terminate at Cloudflare's edge network and require authenticated tunnel sessions before any traffic reaches your server.
Step 5: Preparing the Node.js Foundation
OpenClaw — the agentic AI framework introduced in Part 1 and installed in full in Part 3 — runs on the Node.js JavaScript runtime. Installing Node.js now avoids a dependency gap when you reach the OpenClaw installation steps.
Execute the following commands in sequence:
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version
The first command retrieves the Node.js 24.x repository configuration from the official NodeSource distribution channel. The second installs Node.js. The third verifies the installation.
If the third command returns output in the format v24.x.x — for example, v24.1.0 — the installation was successful. Node.js is now available on your server and ready for Part 3.
If the version command returns an error, re-run the first two commands and try again. If the error persists, confirm that your server is running Ubuntu 24.04 by typing lsb_release -a and verifying the output.
Verifying Your Security Stack
At this point, five of your eight security layers are active. Run the following verification commands and confirm their output.
sudo ufw status verbose
Expected output: "Status: active" followed by rules showing port 80 and port 443 allowed. No other ports should appear as allowed.
sudo systemctl status fail2ban
Expected output: "active (running)" in the status line.
sudo systemctl status cloudflared
Expected output: "active (running)" in the status line.
node --version
Expected output: a version number in the format v24.x.x.
If any of these commands shows a status other than active, return to the relevant step and re-run the installation commands. Most failures at this stage are caused by a missed command or a typo. If you cannot resolve the issue, use Vultr's Reinstall function to return the server to a clean Ubuntu state and start Step 4 again from the beginning. The Cloudflare configuration from Steps 2 and 3 does not need to be redone — it is stored in Cloudflare's dashboard independently of your server's state.
The Security State You Have Built
It is worth being precise about what your server's security posture looks like right now.
From the public internet, your server presents two open TCP ports — 80 and 443 — enforced at both the hardware level by Vultr's firewall and at the operating system level by UFW. Both ports are fronted by Cloudflare's network, meaning inbound traffic on those ports is filtered through Cloudflare's web application firewall and DDoS mitigation before it reaches your server.
Your server's administrative interface — the SSH entry point — has no public port. It is routed through the Cloudflare Tunnel, which is accessible only after completing Cloudflare Access authentication: a verified email address plus a time-limited one-time password. An attacker who does not possess your email credentials cannot initiate the authentication flow.
fail2ban is monitoring authentication logs and will automatically block any IP address generating repeated failed attempts against any service.
Automatic security updates are enabled. Known vulnerabilities in Ubuntu packages will be patched during off-hours without requiring your intervention.
Kernel network hardening settings are active, disabling IP redirect acceptance, source routing, and IP forwarding.
This is not a configuration you bolt on after the fact. It is the foundation on which everything in Parts 3 and 4 is built. Every application you install in subsequent parts inherits this security posture. No application you install will have a public port. No application's administrative interface will be directly accessible from the internet. Every access path routes through the authenticated tunnel.
A Note on OpenClaw
The Node.js installation completed in Step 5 prepares the environment for OpenClaw, which is installed and configured fully in Part 3. Part 1 addressed OpenClaw's disclosed vulnerabilities — CVE-2026-25253 and the ClawJacked class — and explained why the architecture in this guide neutralizes them structurally. That explanation applies here as well.
The security posture you have built in this part is precisely what prevents CVE-2026-25253 from being exploitable in this deployment. The vulnerability requires a publicly accessible WebSocket endpoint. Your server has no publicly accessible ports beyond 80 and 443, both of which are fronted by Cloudflare authentication. OpenClaw, when installed in Part 3, will be bound to localhost and accessible only through the authenticated tunnel. The attack surface the vulnerability requires does not exist here. The architecture built in this part is the reason for that.
What Part 3 Builds
The foundation is complete. The walls are up. The entry points are secured and authenticated.
Part 3 installs the intelligence.
Nextcloud: your private file sync and sharing service, replacing Google Drive and Dropbox with infrastructure you own.
Collabora Online: browser-based collaborative document editing, functionally equivalent to Google Docs, running on your server.
The four-AI unified proxy: a single authenticated web interface through which ChatGPT, Claude, Gemini, and Perplexity are all accessible using API keys that never leave your server.
OpenClaw: the full installation and configuration of your agentic AI butler, including systemd sandboxing, API key isolation, and the messaging integrations that let you issue instructions from any chat application you already use.
When Part 3 is complete, the system will be operational for daily use. The monitoring and remote desktop layers added in Part 4 complete the picture — but Parts 1 through 3 deliver a fully functional, secure, self-hosted AI environment.
Part 3 is next.
Questions, errors, or environment-specific issues belong in the comments. Every one gets read and the technical ones get detailed answers.
— Kusunoki
International Tax Specialist and Systems Builder
Sapporo, Japan
まず誤字・修正箇所を1点指摘します。
誤字・修正箇所
Step 5(Node.jsインストール)のcurlコマンド内にMarkdown記法が混入しています。
現状:
text
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
正:
text
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
Medium版のエディタ上でリンクを貼った際に記法が残ったものと思われます。Medium版も同様に修正が必要です。その他の誤字脱字・重複・冗長表現は検出されませんでした。文章品質は全体的に高いです。
以下、DEV.to特化版の全文です。
text
title: "Laying the Foundation: Vultr, Ubuntu, and Zero-Trust in an Afternoon"
published: false
tags: devops, linux, security, selfhosted
series: Building Your Private AI Infrastructure
Building Your Private AI Infrastructure — Part 2 of 5
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 lose access to their own machine.
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 designed to prevent it — Vultr's Reinstall button returns the server to a clean Ubuntu state in under two minutes. Nothing on your local machine is touched. Nothing on your local machine was ever at risk.
By the end of this part, your server will have zero publicly accessible ports beyond two, an administrative interface invisible to the public internet, and five independent security layers running and verified.
Let's build it.
What You Will Complete in This Part
Five things will be true when this part is done.
You will have a Vultr VPS running Ubuntu 24.04 LTS — your isolated machine in a global data center, accessible from any browser, owned entirely by you.
You will have a custom domain pointing to Cloudflare's network — the address your team uses to reach every service you build.
You will have Cloudflare Zero Trust deployed and active — DDoS mitigation, web application firewall, and authenticated access control, all at zero cost for up to 50 users.
You will have your server's internal defenses configured — UFW firewall, fail2ban intrusion prevention, automatic security updates, and hardened kernel network settings.
You will have Node.js installed and the foundation for OpenClaw — your agentic AI butler — ready for Part 3.
When this part is complete, your server will have five independent security layers active and verified. The sixth, seventh, and eighth layers are completed in Part 3.
Read time: approximately 15 minutes.
Hands-on time: approximately 45 to 90 minutes, depending on your pace.
Prerequisites: Part 1 read and understood. A credit card for Vultr (billed monthly, cancel anytime). An email address you control.
Step 1: Provisioning Your Vultr Server
Vultr is a global cloud infrastructure provider with data centers across North America, Europe, and Asia-Pacific. You are renting a virtual private server — an isolated virtual machine on shared physical hardware, with dedicated RAM, dedicated SSD storage, and no resource contention from other tenants. A VPS is a private apartment in a large building: your own walls, your own keys, your own rules.
Navigate to vultr.com and create an account. Vultr charges by the hour and bills monthly. No contract. Destroy the server and billing stops.
Once your account is created, click Deploy and select Cloud Compute — Shared CPU.
Choose your server location. For a US-based operation, select a data center in Atlanta, Chicago, Dallas, Los Angeles, Miami, New York, or Seattle — whichever is geographically closest to your primary users.
Under Server Image, select Ubuntu 24.04 LTS. This is the Long Term Support release — Canonical commits to security patches through April 2029. LTS releases are the correct choice for production infrastructure: stable, well-documented, maintained on a predictable schedule.
Under Server Size, select your plan based on your team size:
The 1 vCPU / 2 GB RAM / 55 GB SSD plan at approximately $12/month is sufficient for a single user evaluating the system.
The 2 vCPU / 4 GB RAM / 80 GB SSD plan at approximately $24/month is the recommended configuration for three to eight concurrent users with the full stack running.
The 4 vCPU / 8 GB RAM / 160 GB SSD plan at approximately $48/month handles eight to thirty users under normal business workloads.
Under Additional Features, enable IPv6 — it costs nothing and is relevant for some services in Part 3.
Under Server Hostname, enter something meaningful: your business name, a project name, or simply myserver. Visible only in your dashboard.
Under Root Password, set the master credential for your server. Use a randomly generated password of at least 20 characters — uppercase, lowercase, numbers, and symbols. Something like Kx9mP2wL@vN7qR5jT! in structure, with your own random characters. Do not use your name, your business name, a dictionary word, or any variation of "password."
Store this in a password manager. Bitwarden is free, open-source, and recommended. If you do not yet use a password manager, this is the moment to start — you will generate several strong credentials during this build.
Click Deploy Now. The server provisions within 60 seconds. When status shows Running, your private infrastructure exists. Note the IP address in your dashboard — you will need it in Step 3.
Step 2: Registering Your Domain
A domain name is the address your team uses to reach every service in this stack. Without one, services are reachable only by IP address — unmemorable, difficult to secure with HTTPS, unsuitable for professional use.
With a domain:
text
cloud.yourdomain.com → your private file sync
ai.yourdomain.com → your unified AI interface
remote.yourdomain.com → your remote desktop gateway
grafana.yourdomain.com → your monitoring dashboard
Navigate to cloudflare.com/products/registrar. Cloudflare Registrar is recommended specifically because it consolidates your domain and your security layer in one dashboard — one less point of configuration error. .com domains run approximately $10.44 per year at Cloudflare's cost-plus pricing. Other registrars work equally well if you have an existing preference.
Search for your preferred domain name. Choose something short, professional, and easy to communicate verbally — you will type it into terminal commands and read it aloud. If your first choice is taken, have three or four alternatives ready.
Complete the registration. This domain is used throughout Parts 2 through 5.
Step 3: Deploying Cloudflare Zero Trust
Cloudflare routes approximately 20% of global web traffic through its systems. The Zero Trust free tier — available for organizations with up to 50 users — provides enterprise-grade capabilities that would cost tens of thousands of dollars per year from commercial security vendors.
What you are deploying in this step: the outermost layer of your security architecture. A web application firewall and DDoS mitigation system that filters all inbound traffic before it reaches your server's IP address. An access control layer that authenticates every user before any request reaches any service.
Creating Your Cloudflare Account
If you registered your domain through Cloudflare Registrar in Step 2, your account already exists. If you used another registrar, navigate to dash.cloudflare.com and create a free account.
Immediately after logging in, enable two-factor authentication. Navigate to My Profile, then Authentication, then Two-Factor Authentication. Install Google Authenticator or Authy on your phone — both are free — and follow the setup flow. If your Cloudflare account is compromised, an attacker can modify the security layer protecting your entire stack. Two-factor authentication is the single most effective step you can take to prevent that.
If you used a registrar other than Cloudflare, add your domain now: click Add a Site, enter your domain name, select the Free plan, and follow the prompts. Cloudflare will display two nameserver addresses — for example, ada.ns.cloudflare.com and ben.ns.cloudflare.com. Log into your registrar and update your domain's nameserver records to these two addresses. Propagation takes between a few minutes and 24 hours. Cloudflare's dashboard shows Active when the change has propagated.
Setting Up Zero Trust
In your Cloudflare dashboard, click Zero Trust in the left navigation panel. Choose a team name — a short alphanumeric identifier such as your business name, for example mybase. Select the Free plan. Complete the setup flow.
Creating the Tunnel
The Cloudflare Tunnel is the architectural element that makes this security model possible. Rather than opening ports on your server for incoming connections — which creates attack surface — the tunnel works in reverse: your server initiates an outbound connection to Cloudflare's network and maintains it. All inbound access to your services routes through this tunnel. Your server's IP address is never directly exposed. There is nothing for a port scanner to find.
In the Zero Trust dashboard, navigate to Networks, then Tunnels. Click Create a tunnel, select Cloudflared, and name your tunnel — for example, mybase-tunnel. On the next screen, select Debian/Ubuntu as the operating system. Cloudflare will display a single command — a long string beginning with curl. Copy this entire command.
Now open your server's console. In your Vultr dashboard, click on your server, then click Console. A terminal window opens in your browser. This is a direct connection to your server's command line.
You will see a login prompt. Type root and press Enter. Type your root password and press Enter. The password field shows nothing as you type — this is intentional security behavior, not a malfunction. The characters are recorded; they are not displayed.
Once logged in, paste the command you copied from Cloudflare and press Enter. The installation takes approximately 30 seconds. When it completes, return to the Cloudflare dashboard. The tunnel status will show Healthy. Your server and Cloudflare are now connected through an encrypted, authenticated channel that runs entirely from your server outward. No inbound ports required. Nothing to scan from outside.
Configuring Tunnel Routing
The tunnel is a conduit. You now need to tell it where to route traffic for each subdomain. In the Cloudflare tunnel configuration, click the Public Hostname tab and add the following entries. Replace yourdomain.com with your actual domain name throughout.
text
cloud.yourdomain.com → http://localhost:8080 (Nextcloud)
office.yourdomain.com → http://localhost:9980 (Collabora Online)
ai.yourdomain.com → http://localhost:8000 (unified AI proxy)
remote.yourdomain.com → http://localhost:8888 (Apache Guacamole)
grafana.yourdomain.com → http://localhost:3000 (Grafana monitoring)
ssh.yourdomain.com → ssh://localhost:50922 (SSH via tunnel)
The term localhost in each entry means "this server itself." The number following the colon is the port — a room number within the server. Traffic arriving through the tunnel for cloud.yourdomain.com is directed to port 8080 on the server's internal interface, where Nextcloud will be listening. The service never communicates directly with the public internet. The tunnel handles all external communication.
Configuring Access Policies
The tunnel controls routing. Access policies control who is permitted to initiate a session through the tunnel.
In the Zero Trust dashboard, navigate to Access, then Applications. For each subdomain listed above, create a Self-hosted Application. Set the domain to the corresponding subdomain. Under Authentication, select One-time PIN as the identity provider.
The one-time PIN method: when a user navigates to cloud.yourdomain.com, Cloudflare presents an authentication screen. The user enters their email address. Cloudflare sends a six-digit code to that address. The user enters the code. If the email address is in the policy's allowed list, access is granted for a configurable session duration. No password to manage. No identity provider to configure. No user account to create. The email address is the credential.
Under Include in the policy rule, add the email addresses of everyone who should have access to that service. You can add and remove addresses at any time. Changes take effect immediately.
For services that should be accessible only to you — the SSH gateway, for example — restrict the policy to your email address alone.
Granting a colleague access to your private cloud: add their email address to the cloud.yourdomain.com policy. They navigate to the URL, enter their email address, receive a six-digit code, enter it, and they are in. No VPN client installation. No shared password. No user account provisioning beyond adding an email to a list.
Step 4: Hardening the Server
Cloudflare is the outer wall. The server itself needs independent defenses — not because Cloudflare will fail, but because defense in depth means no single layer's failure compromises the whole.
The following commands are executed in the server console, one by one. Paste each command, press Enter, wait for it to complete, then proceed to the next.
Creating an Administrative User
The root account is the server's master key. Operating as root for daily administration means that a typo — deleting a file with a slightly malformed command — can cause irreversible damage without a confirmation prompt.
Create a dedicated administrative user and reserve root for initial setup only:
bash
adduser myadmin
You will be prompted for a password. Use a strong, randomly generated password of at least 20 characters — different from your root password and stored in your password manager. The prompts for Full Name and similar fields can be left blank by pressing Enter.
Grant this user administrative privileges:
bash
usermod -aG sudo myadmin
The name myadmin is a placeholder. Replace it with any name you prefer. Use your chosen name wherever myadmin appears in subsequent commands throughout this guide.
Configuring the UFW Firewall
UFW — Uncomplicated Firewall — is Ubuntu's built-in firewall manager. You are configuring it to allow inbound connections on port 80 and port 443 only. Every other port will be blocked.
bash
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
When prompted to confirm enabling the firewall, type y and press Enter.
Note what is absent: port 22 for SSH is not opened. In a conventional server setup, SSH on port 22 is the administrative entry point — and one of the most frequently probed ports on the internet. In this architecture, SSH administration is routed through the Cloudflare Tunnel, which means the administrative interface is not visible to the public internet at any port. There is nothing to probe. This is a fundamental architectural advantage over VPN-based setups, where the VPN port must itself be exposed.
Two ports open. That is the entire external attack surface.
Installing fail2ban
fail2ban monitors authentication logs and automatically blocks IP addresses that generate repeated failed login attempts. It is an autonomous intrusion prevention system that operates continuously without requiring attention.
bash
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
Those two commands install fail2ban, configure it to start automatically on boot, and start it immediately. If any automated script or human attacker attempts to brute-force any authentication endpoint on your server, fail2ban will detect the pattern and block the source IP before the attempt can succeed.
To confirm it is running:
bash
sudo systemctl status fail2ban
The output should show active (running). If it does not, re-run the enable command and check for error output.
Enabling Automatic Security Updates
Software vulnerabilities are discovered continuously. Patches are released continuously. Manually applying security updates to a production server every day is not a realistic operational model.
The unattended-upgrades package configures Ubuntu to download and apply security patches automatically — specifically security patches, not general software updates, which can occasionally introduce breaking changes.
bash
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
A dialog will appear asking whether to enable automatic updates. Select Yes. The system now applies security patches during off-hours without requiring you to log in, check for updates, or schedule maintenance windows.
Hardening Kernel Network Settings
The Linux kernel's network stack has configurable parameters that control how it responds to certain classes of potentially malicious network traffic. The following settings disable IP redirect acceptance, source routing, and SYN flood amplification — attack vectors that are rarely relevant to legitimate traffic but frequently exploited in network-layer attacks.
Open the configuration file:
bash
sudo nano /etc/sysctl.d/99-security.conf
Paste the following block exactly as written:
text
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
To save: press Ctrl+O, then Enter to confirm the filename. To exit nano: press Ctrl+X.
Apply the settings immediately:
bash
sudo sysctl --system
A note on net.ipv4.ip_forward = 0: in a VPN-based server configuration, IP forwarding must be enabled so that the VPN can route packets between the tunnel and the network. In this architecture, Cloudflare Tunnel handles all external routing through an outbound connection only. IP forwarding on the server itself is unnecessary and is therefore disabled. Capability not needed is capability that cannot be exploited.
Configuring the Vultr Hardware Firewall
UFW operates at the Ubuntu software level. Vultr also provides a hardware-level firewall that filters traffic before it reaches your operating system at all — an independent enforcement of the same port restrictions that holds even if the software firewall has a configuration error.
In your Vultr dashboard, navigate to your server's detail page, then to Firewall. Create a new firewall group with the following rules:
text
Accept inbound TCP on port 80 from any source.
Accept inbound TCP on port 443 from any source.
Drop all other inbound traffic.
Apply this firewall group to your server.
Your server now has two independent firewalls enforcing the same two-port restriction: Vultr's hardware firewall at the infrastructure layer and UFW at the OS layer. Both ports terminate at Cloudflare's edge network and require authenticated tunnel sessions before any traffic reaches your server.
Step 5: Preparing the Node.js Foundation
OpenClaw — the agentic AI framework installed in full in Part 3 — runs on the Node.js JavaScript runtime. Installing Node.js now avoids a dependency gap when you reach those steps.
bash
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version
The first command retrieves the Node.js 24.x repository configuration from the official NodeSource distribution channel. The second installs Node.js. The third verifies the installation.
If the third command returns output in the format v24.x.x — for example, v24.1.0 — the installation was successful.
If the version command returns an error, re-run the first two commands and try again. If the error persists, confirm your server is running Ubuntu 24.04:
bash
lsb_release -a
Verifying Your Security Stack
At this point, five of your eight security layers are active. Run the following verification commands and confirm their output.
bash
sudo ufw status verbose
Expected: Status: active, followed by rules showing port 80 and port 443 allowed. No other ports should appear as allowed.
bash
sudo systemctl status fail2ban
Expected: active (running) in the status line.
bash
sudo systemctl status cloudflared
Expected: active (running) in the status line.
bash
node --version
Expected: a version number in the format v24.x.x.
If any command shows a status other than active, return to the relevant step and re-run the installation commands. Most failures at this stage are caused by a missed command or a typo. If you cannot resolve the issue, use Vultr's Reinstall function to return the server to a clean Ubuntu state and start Step 4 again from the beginning. The Cloudflare configuration from Steps 2 and 3 does not need to be redone — it is stored in Cloudflare's dashboard independently of your server's state.
The Security State You Have Built
It is worth being precise about your server's security posture right now.
From the public internet, your server presents two open TCP ports — 80 and 443 — enforced at both the hardware level by Vultr's firewall and at the OS level by UFW. Both ports are fronted by Cloudflare's network: inbound traffic is filtered through Cloudflare's web application firewall and DDoS mitigation before it reaches your server.
Your server's administrative interface — the SSH entry point — has no public port. It routes through the Cloudflare Tunnel, accessible only after completing Cloudflare Access authentication: a verified email address plus a time-limited one-time password. An attacker without your email credentials cannot initiate the authentication flow.
fail2ban is monitoring authentication logs and will automatically block any IP address generating repeated failed attempts.
Automatic security updates are enabled. Known vulnerabilities in Ubuntu packages will be patched during off-hours without requiring your intervention.
Kernel network hardening is active, disabling IP redirect acceptance, source routing, and IP forwarding.
This is not security bolted on after the fact. It is the foundation on which everything in Parts 3 and 4 is built. Every application you install in subsequent parts inherits this security posture. No application you install will have a public port. No application's administrative interface will be directly accessible from the internet. Every access path routes through the authenticated tunnel.
A Note on OpenClaw
The Node.js installation in Step 5 prepares the environment for OpenClaw, installed and configured fully in Part 3. Part 1 addressed OpenClaw's disclosed vulnerabilities — CVE-2026-25253 and the ClawJacked class — and explained why this architecture neutralizes them structurally.
The security posture you built in this part is precisely what prevents CVE-2026-25253 from being exploitable in this deployment. The vulnerability requires a publicly accessible WebSocket endpoint. Your server has no publicly accessible ports beyond 80 and 443, both fronted by Cloudflare authentication. OpenClaw, when installed in Part 3, will be bound to localhost and accessible only through the authenticated tunnel. The attack surface the vulnerability requires does not exist here.
What Part 3 Builds
The foundation is complete. The walls are up. The entry points are secured and authenticated.
Part 3 installs the intelligence.
Nextcloud: your private file sync and sharing service, replacing Google Drive and Dropbox with infrastructure you own.
Collabora Online: browser-based collaborative document editing, functionally equivalent to Google Docs, running on your server.
The four-AI unified proxy: a single authenticated web interface through which ChatGPT, Claude, Gemini, and Perplexity are all accessible using API keys that never leave your server.
OpenClaw: the full installation and configuration of your agentic AI butler, including systemd sandboxing, API key isolation, and the messaging integrations that let you issue instructions from any chat application you already use.
When Part 3 is complete, the system is operational for daily use. The monitoring and remote desktop layers added in Part 4 complete the picture — but Parts 1 through 3 deliver a fully functional, secure, self-hosted AI environment.
Part 3 is next.
Questions, errors, or environment-specific issues belong in the comments. Every one gets read and the technical ones get detailed answers.
— Kusunoki
International Tax Specialist and Systems Builder
Sapporo, Japan
Top comments (0)