Building & Deploying AI Apps: Infrastructure Guide (VPS, Security, Monitoring, Costs)
Published: December 27, 2025
I build AI & automation tools and manage VPS, DNS, security, databases, auth, infra - the full chain. Working setups below - for data scientists, analysts, and small businesses deploying their own tools.
30+ live AI & Automation apps. Open source, publicly available on this site tigzig.com
Fourth in my 2025 learnings series on building and deploying AI apps. full cycle of AI apps from build to live deployment.
STRATEGIC CHOICES
Skipped AWS and Azure
Too expensive, too complicated for my needs. These are aircraft carriers. My requirements fit a Toyota.
I work with small businesses. Don't need 'Enterprise Level' or 'At Scale' yet. When that changes, I'll move. Until then, simpler providers work fine.
I keep small AWS/Azure instances running for client testing and compatibility checks. But my production apps run elsewhere.
Hetzner as primary VPS
Chose Hetzner for clean UI, solid performance, straightforward pricing, simple setup.
Server that I use to host tigzig.com backend - CAX21 (ARM-based)
- 4 vCPUs
- 8GB RAM
- 80GB disk
- €5.99/month
Currently hosting:
- 30+ FastAPI backends
- 2 instances of n8n
- 2 instances of Coolify
- Still ~30% capacity remaining
SECURITY : SERVER & FRONTEND
Defended a bot attack with Fail2ban
A few months after setup, got hit with a bot attack - rotating proxies, thousands of SSH login attempts. Server load spiked, had to restart.
I already had Fail2ban running but with loose parameters. Tightened the config:
Current Fail2ban settings:
- maxretry: 5 attempts
- findtime: 3600 seconds (1 hour window)
- bantime: 86400 seconds (24 hour ban)
- Backend: nftables
Results after tightening:
- Currently banned: 157 IPs
- Total banned since last server restart a week back: 1,223 IPs
- Total failed attempts blocked: 6,082
Attack stopped. No issues since.
Layered firewall with UFW
Hetzner has built-in firewall. I added UFW (Uncomplicated Firewall) on the server following the video guide, but in hindsight Hetzner firewall alone is sufficient - this was redundant.
UFW config:
- Default incoming: DENY
- Default outgoing: ALLOW
- Allowed ports: 22 (SSH), 80 (HTTP), 443 (HTTPS)
- Docker bridge networks: allowed (172.17.0.0/16, 172.18.0.0/16)
SSH hardening
Password auth completely disabled. Root login via SSH keys only.
SSH config:
- PermitRootLogin: prohibit-password
- PasswordAuthentication: no
- PubkeyAuthentication: yes
- KbdInteractiveAuthentication: no
No password = no brute force risk.
Automatic security updates enabled
unattended-upgrades package installed and active. Security patches apply automatically. One less thing to monitor.
Three baseline security rules for every backend
- CORS: configured per use case (sometimes loose, sometimes strict - depends on app)
- Rate limiting: SlowAPI middleware, default limits on all endpoints
- API keys: for non-browser access (programmatic clients)
Browser access = CORS check. Non-browser = API key required.
Frontend Security: API Keys
Environment variables in React get bundled into client build - visible to anyone. Not secure for API keys or backend endpoints.
Solution: Server-side execution
1. Vercel API Routes (for quick tasks <5 min)
Serverless functions run server-side. Frontend calls your route, which holds sensitive variables and makes external API calls. Keys stay hidden. 5-minute execution limit on free tier.
2. Polling (what I use for long tasks)
Route initiates job, returns ID. Frontend polls status every 10-15 seconds via separate route. Backend processes however long needed - no timeout. Requires job queue and status endpoints.
3. Full server-side rendering (client case)
One client: PHP with server-side rendering. All processing happens server-side. Browser sees rendered HTML only. No React, no exposure issues.
4. Self-hosted options (haven't tried)
Next.js SSR on Vercel still hits 5-minute limit. Self-hosted Next.js on Coolify - no timeout, continuous Node server. FastAPI on Coolify works similarly.
Authentication: Auth0 currently, exploring Clerk
Some apps need user auth. Using Auth0 now - works but can get complicated with callback URLs and React frontend integration. Exploring Clerk as alternative but haven't tested yet.
DEPLOYMENT & HOSTING
Coolify = self-hosted Render
Point to GitHub repo, Coolify deploys each backend in its own Docker container. Seamless.
Each FastAPI backend gets isolated container, auto-restarts on crash, logs accessible via UI.
Flowise via docker custom image
Deployed Flowise via a custom docker image built for ARM64 architecture of my Hetzner server, as the official Flowise image was for AMD64 (x86). Manually triggered via Github Actions.
n8n via docker compose
n8n via a docker compose - UI worked fine through the reverse proxy, but webhooks weren't reachable from outside - external services couldn't callback to my n8n instance. The fix required a few changes to the compose file:
Custom DNS - Added dns: 1.1.1.1, 8.8.8.8 to force the container to use external DNS instead of Docker's internal resolver
Privileged mode - Set privileged: true to give the container elevated network permissions needed for proper routing behind the proxy.
Configured WEBHOOK_URL and N8N_EDITOR_BASE_URL environment variables so n8n knows its public URL when generating webhook endpoints.
Without these changes, n8n runs but can't communicate with the outside world - a common gotcha when self-hosting behind reverse proxies.
Vercel for frontends
40+ UIs on Vercel free tier. Fast, reliable, zero config deployments. No reason to self-host static frontends when Vercel does it better.
My top recommended resource for Hetzner + Coolify setup
This guide walked me through the entire security hardening process: https://www.youtube.com/watch?v=taJlPG82Ucw
I could have used an AI coder with CLI access now, but when I set this up, this video + ChatGPT got me through it step-by-step.
DNS, DOMAIN & CLOUDFLARE
Keep domain registrar separate from DNS
Domains registered on: Namecheap or GoDaddy
DNS management: Cloudflare
Reason: If Cloudflare has issues, I can quickly point DNS elsewhere. If registrar has issues, DNS still works.
Migrated 100+ DNS records to Cloudflare
Migration was seamless. Cloudflare lets you import/export DNS record files. Moved everything in one shot.
DNS management is straightforward
Set routing rules, configure caching, manage SSL - all in one dashboard. Clean UI.
I'm using a fraction of what Cloudflare can do, but what I use works well.
Cloudflare proxy: 100-second timeout limit
Free tier has 100-second timeout for proxied requests.
Problem: Some of my backends run 5-10 minutes (heavy data processing, large file uploads).
Solution: Remove those endpoints from Cloudflare proxy, point directly to server. Manage security at FastAPI level (CORS, rate limits, API keys).
Most backends are proxied. Long-running ones are direct.
Free tier SSL: one subdomain level only
Cloudflare free tier handles SSL for:
- app.tigzig.com ✓
- api.tigzig.com ✓
But NOT for:
- hosting.app.tigzig.com ✗
Multi-level subdomains require paid tier for SSL certificates. Plan accordingly.
Caching rules for static content
Set up custom cache rules for:
- Blog posts (1 month TTL)
- Large datasets (1 month TTL)
After deploying new blog posts, I run a cache purge + warm script. Purges old cache, warms new content. Users see updates immediately instead of waiting for TTL expiry.
Cloudflare caching for large files
Some apps serve 1GB+ datasets. Hosting on Hetzner gives decent speed. Hosting via Cloudflare cache gives better speed. Files still live on my server, but Cloudflare edge caching improves delivery.
MONITORING
Built a custom app for monitoring all my FastAPI backends.
Frontend: React dashboard
Built simple React dashboard to view:
- API success/failure rates
- Response times
- Endpoint usage
Deployed on Vercel. Pulls from Neon database.
Created PyPI package for API logging
Built custom FastAPI middleware: tigzig-api-monitor
Published to PyPI: https://pypi.org/project/tigzig-api-monitor/
Why a package? I was copying the same logging code across 30+ backends. Package = import once, use everywhere.
What the package collects
- App name
- Endpoint path (no query params)
- HTTP method
- Response status code
- Response time (milliseconds)
- Client IP (hashed - see next point)
- User-Agent
- Origin
- Referer path (no query params)
IP hashing = no PII stored
IPs are hashed before storage. Can't reverse-engineer original IP. Privacy by design.
Geolocation tracking: done separately using GeoLite2 free database. Not very accurate, but works for basic country-level tracking.
Non-blocking async logging
Logging happens asynchronously. API requests don't wait for log writes. If logging fails, API still works.
Database: PostgreSQL on Neon
All API logs go to PostgreSQL on Neon.com.
Neon free tier: 40-50 projects, 500MB each. Perfect for log storage across multiple apps. Currently on paid tier temporarily for higher limits, but free tier worked fine for months.
Web analytics: PostHog
Migrated from StatCounter to PostHog.
StatCounter fine for low traffic. With increasing visitors, needed better dashboards and event tracking.
PostHog setup: cloud version, free tier. Easy to configure, customizable dashboards.
Brevo for automated emails
Email not a major requirement for my apps. Occasionally need notification emails (user action triggers alert to me).
Using Brevo free tier. Works fine for low-volume transactional emails. Not using for campaigns or marketing - just automated notifications.
SELF-BUILT TOOLS
Blog automation: markdown to HTML pipeline
Used to host blog on managed service. Migrated out. Now self-hosted with custom pipeline.
Process:
- Write in markdown
- Run script - script converts markdown → styled HTML
- Purge + warm Cloudflare cache
Default to custom tools now
Earlier, I'd use a microservice or SaaS tool for file conversion, scraping, monitoring. Now I just build it. FastAPI backend + React frontend + deploy via Coolify. Easier to maintain, no vendor dependencies, full control.
Examples:
- Blog editor
- API log monitor
- File converters
- Web scrapers
Total build time with AI coders: few hours to a day for simpler tools. More for complex ones. Maintenance: minimal.
BACKUP STRATEGY
Hetzner 7-day backups enabled
Automatic snapshots, 7-day retention. Costs extra but worth it.
Backups exist. Haven't needed them yet. Should test restoration process - haven't done it.
No comprehensive backup strategy
Don't have mirror site or off-site backups. Everything critical is in Git repos.
This is a gap. Should improve. Haven't prioritized it yet.
COSTS
Hetzner VPS: €7.69/month
Includes 7-day backups. Hosting 30+ backends, n8n, Coolify. Still 30% capacity left.
AWS: ~$5/month for shut-off instances
I maintain an EC2 instance and MySQL RDS for client testing. Both stay shut off unless needed (few times a month).
Still get charged ~$5/month for baseline costs - IP allocation, DNS, other AWS oddities. Small price to keep testing environment ready.
Vercel: Free tier
40+ React frontends. No cost.
Neon PostgreSQL: Free tier (currently paid)
Was on free tier for months. Temporarily on paid for higher limits. Will likely drop back to free.
Cloudflare: Free tier
DNS, caching, basic security. No cost.
PostHog: Free tier
Web analytics. No cost.
Brevo: Free tier
Email notifications. No cost.
Claude Code Max: $100/month - biggest cost, worth every penny
This is like having a team of developers. Cloud engineering, Python, FastAPI, React - covered.
With CLI and API access, it now manages GitHub workflows, server operations, deployment scripts. I barely touch the command line manually anymore.
Worth it? Absolutely. $20 keeps servers running. $100 gives me a full dev team. The multiplier is massive.
KEY TAKEAWAYS
Start simple, scale when needed
Don't jump to AWS/Azure until you actually need their scale. Smaller providers work fine for most use cases.
Security is not optional
Fail2ban, SSH hardening, automatic updates. Set these up early. Defending attacks after the fact is painful.
Self-host what you can, use SaaS where it's better
VPS + deployments = Hetzner + Coolify
Frontends = Vercel
Databases = Neon
DNS/CDN = Cloudflare
Pick the right tool for each layer.
Build custom tools when you need control
Blog automation, API monitoring, file processing - built custom. Took hours with AI coders, now fully under my control.
Test your backups
I haven't. Should. Don't be me.
RESOURCES
Hetzner + Coolify setup guide:
https://www.youtube.com/watch?v=taJlPG82Ucw
Live apps (30+ micro-apps): Open Source - Hit 'Docs' for source codes tigzig.com