Self-Hosted Cloud Server Stack
CldEnv is a Docker Compose stack for running your own server on a free-tier VPS: automation, AI chat and local inference, git hosting, container/uptime monitoring, a file browser, and a set of developer utilities, all behind one reverse proxy, with your data staying on your own server.
This repository provides the configuration patterns, scripts, and guides to deploy this stack on a free Oracle Cloud instance or any standard VPS.
- Reverse proxy: Caddy - TLS and routing for every service below.
- Automation: pick one -- n8n (visual, node-based workflows; what this repo's example compose ships) or Windmill (script-first, Python/TypeScript/Bash jobs with built-in scheduling; what the reference deployment behind this tutorial actually runs today). Both are included as separate, clearly-labeled blocks in
docker-compose.example.yml-- keep the one you want, delete the other. - AI chat: Open WebUI - a ChatGPT-style chat UI, backed by Ollama for free local inference by default, with free cloud models as an optional add-on, and Qdrant for vector search.
- Git hosting: Gitea - a self-hosted git server.
- Container management: Portainer - a web UI for Docker.
- Monitoring: Uptime Kuma (service uptime) and Beszel (resource metrics).
- Files: File Browser - a web file manager.
- Developer utilities: IT-Tools (everyday dev conversions/generators) and ChangeDetection.io (page-change monitoring).
- Housekeeping: Watchtower (update monitoring) and a keepalive container for free-tier instance reclamation.
- Orchestration: Docker Compose.
This stack is optimized for the Oracle Cloud Always Free tier, specifically the ARM64 Ampere instances. Starting from zero -- no Oracle account yet, or unsure how to actually provision the instance -- see the Oracle Cloud Setup Guide first; it covers account creation, current resource limits, and the free-tier capacity issues that trip up most people before they ever get to Docker.
- Instance: VM.Standard.A1.Flex
- CPU: 2 OCPUs (ARM64) -- Oracle's Always Free ARM allocation was reduced in 2026; see the setup guide for what changed and why 2 (not 4) is the safe number to provision.
- RAM: 12 GB.
- Storage: 200 GB, assigned to this instance's boot volume.
- Tip: The 200 GB is a tenancy-wide pool of combined boot and block volume storage in your home region -- not a 200 GB block volume per instance. Every volume draws from it, including the boot volume of any second instance (50 GB by default, 47 GB minimum for any shape). Put all 200 GB here for maximum headroom (Docker images, logs, vector DBs), or split it if you plan on a second free instance -- though that second instance also has to share the same 2 OCPU / 12 GB compute allocation. Snapshots come out of a separate allowance: five volume backups total, boot and block combined.
- OS: Ubuntu 22.04 or 24.04 (ARM64).
While optimized for Oracle ARM, this stack runs perfectly on any x86/ARM VPS (DigitalOcean, Hetzner, AWS) with Docker installed.
Each service in Caddyfile.example gets its own subdomain (ai.example.com, git.example.com, etc.). Caddy is what routes each one to the right container once DNS resolves -- it isn't involved in making the DNS itself work. Either path below gets you there; pick whichever matches what you already have.
Option A: You own a domain (recommended if you have one)
Most registrars and DNS providers support wildcard records, which cover every subdomain in one shot:
- In your domain's DNS settings, add a single A record: host
*, value your server's public IP (e.g.,*.example.com -> 203.0.113.10). - That's it --
ai.example.com,git.example.com, and every other subdomain inCaddyfile.examplenow resolve automatically, present or future, with no further DNS changes. - If your provider doesn't support wildcards, add one A record per subdomain instead.
Option B: Free subdomain via DuckDNS
DuckDNS behaves like a wildcard once you've registered one name -- it resolves any subdomain under that name to the same IP automatically, with nothing extra to configure (confirmed directly with dig against a live DuckDNS domain: an arbitrary, never-registered subdomain resolved correctly with zero prior setup).
- Get a free domain from
duckdns.org(e.g.,my-ai-stack.duckdns.org), pointed at your server's IP. - That's it --
ai.my-ai-stack.duckdns.org,git.my-ai-stack.duckdns.org, and every other subdomain inCaddyfile.examplealready resolve to that same IP, present or future, with no further DNS changes. The dashboard's "domains X/5" counter is how many separate root names you've registered (useful for running entirely separate projects), not a limit on subdomains under the one you're using here.
Either way, the included Caddyfile.example shows the routing for every service once DNS resolves -- Caddy requests and renews TLS certificates automatically, the same way, regardless of which option you used.
- A running VPS you can SSH into. On Oracle Cloud, that means having already worked through the Oracle Cloud Setup Guide -- account creation, current resource limits, and the capacity issues that block most people before this point aren't covered again here.
- Docker & Docker Compose.
- A domain name (or DuckDNS subdomain).
- On Oracle Cloud specifically: ports 80 and 443 also need opening in the instance's own Security List / Network Security Group (Networking > Virtual Cloud Networks in the OCI console) -- this is a separate firewall from the instance's own
ufw, and traffic gets silently dropped at this layer if it's not opened here too, regardless of howufwis configured.
If you are on a fresh Oracle Ubuntu instance, you can install the latest Docker engine quickly:
# 1. Update and Install Essentials
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git ufw
# 2. Install Docker (Official Script)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# 3. Enable Non-Root Docker Access (Vital!)
# Allows running 'docker' without 'sudo'
sudo usermod -aG docker $USER
newgrp docker
# 4. Verify
docker run hello-worldClone this repository to your server:
git clone https://github.com/simien/CldEnv.git
cd CldEnvWe provide example configurations that need to be customized. example.com appears in both files below -- replace every instance of it in both, not just one.
A. Networking (Caddy)
cp Caddyfile.example Caddyfile
nano Caddyfile- Replace
example.comwith your actual domain/subdomain. - Update the email address for Let's Encrypt notifications.
- Fix up the basic-auth line on the
tools.route (and any others you add one to): generate a real hash after Caddy is running, withdocker exec caddy caddy hash-password, and paste it in.
B. Secrets (.env)
cp .env.example .env
nano .env- Fill in
WEBUI_SECRET_KEY(required). Local models via Ollama need no key at all; if you want cloud models too,GEMINI_API_KEYis the free option (see Model Registry for why). See the comments in.env.examplefor every variable and which ones are optional. - Docker Compose loads
.envautomatically from this directory -- no extra flag or step needed.
C. Services (Docker)
cp docker-compose.example.yml docker-compose.yml
nano docker-compose.yml- Replace
example.comhere too (see the note above). - Pick your automation engine: delete the
n8nblock or thewindmill_server/windmill_lsp/windmill_dbblocks (see Architecture above), plus their matching Caddy route.
D. Local AI (Ollama) To enable local RAG and chat, pull the essential models:
# Embeddings (Required for RAG)
docker exec -it ollama ollama pull nomic-embed-text
# Chat (Optional Local Fallback)
docker exec -it ollama ollama pull qwen2.5:14b
# or for smaller instances
docker exec -it ollama ollama pull llama3.2Start the stack:
docker compose up -dThe services are now running:
- n8n:
https://example.com(or configured subdomain) -- if you kept n8n - Windmill:
https://windmill.example.com-- if you kept Windmill instead - Open WebUI:
https://ai.example.com
- Oracle Cloud Setup: Account creation, current Always Free limits, and getting past "Out of Host Capacity" -- start here if you don't have a running instance yet.
- Model Registry: How to configure Ollama and OpenRouter.
- Open WebUI Setup: First-login admin setup and connecting models.
- Oracle Cloud Knowledgebase: Full service reference, routing table, AI strategy, and troubleshooting.
MIT