Guide
Build and self-host your own AI app
One small server, Coolify, a private GitHub repo, Replicate, and a coding agent that keeps going until the app is live. Eight checkpoints.
Contents
1 of 8
See the whole system
You are renting a computer on the internet. Coolify gives it a deployment dashboard. The rest is code, model access and clear instructions.
VPS
Coolify
GitHub
Replicate
The coding agent does the repetitive part. It builds the app, pushes the code, configures Coolify, deploys, watches the logs and tests the live URL. You own the accounts, approve access and keep the secrets.
2 of 8
Rent a small server
Hetzner is an easy start, but any Ubuntu-compatible VPS works. Start with enough headroom for builds, then resize when real usage says so.
Pick x86 / AMD64
Small first, resize later
Select during creation
- A location near you or your users.
- An SSH key. SSH is the encrypted connection your terminal uses to control the server.
- Ubuntu 24.04 LTS, 64-bit.
- Hetzner Cloud Firewall and Backups. Daily backups use seven rotating slots. Your app data still needs its own tested backup.
- A clear name such as
apps-01.
3 of 8
Secure the basics, then install Coolify
This is the minimum sensible setup. You are removing easy risks, not becoming a sysadmin.
3.1 Update the fresh server
Connect with the key you added, install updates, reconnect after the reboot.
ssh root@<SERVER_IP> apt update apt upgrade -y reboot
Keep key-based SSH. When you are comfortable, create a named sudo user, verify it in a second terminal, then disable password SSH and root password login. Do not close your working session until the new login works. If an agent makes the change, make it show the effective SSH settings before reloading the service.
3.2 Add firewall rules
Use your provider's firewall. Docker networking can bypass rules made only with UFW. Coolify's firewall page lists the ports and when they can close.
Once the dashboard has a working HTTPS domain, Coolify says you can close 8000, 6001 and 6002. Keep 22, 80 and 443.
3.3 Run the installer
Use a fresh server. Check the installation page first in case prerequisites change.
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash
3.4 Point a domain at it
- Create an A record such as
coolify.example.compointing to the server's IPv4 address. - Set that full
https://URL in Coolify settings. - Create another A record for the app domain. Several domains can point at one server.
- Wait for DNS, then let Coolify request and renew the certificate.
References: DNS configuration and domains and HTTPS.
SQLite needs a real home
/app/data, mount a Coolify volume there, run one replica. Containers are replaceable. The volume survives redeploys. Never share one SQLite file between replicas.Health checks need a boring answer
GET /api/health. Return 200 only when the app can reach SQLite, with a small JSON body and no secrets. Set the same path in Coolify's health check.sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab free -h
Back up both layers. Coolify's own settings and the application volume. An instance backup does not include volume data. For SQLite, use an application-aware backup or pause writes while copying, store a copy off the server, and test a restore. See persistent storage and backup and restore.
4 of 8
Connect GitHub and Replicate
Create the accounts, then grant the narrowest access that lets one app deploy.
GitHub
Replicate
Give Coolify access to the private repo
Recommended
Coolify GitHub App
One-repo fallback
Read-only deploy key
Create a Coolify API token only if the agent will deploy
- In Coolify, enable API access under Settings, Advanced.
- Open Security, API Tokens. Give it a short expiry and only the permissions needed.
- For an agent creating and deploying an app that usually means read, write and deploy. Avoid root and
read:sensitiveunless an endpoint proves it needs them. - Store the token once. The base URL is your Coolify URL followed by
/api/v1.
Check current permission names in the API authorization guide. Tokens are scoped to the active team.
5 of 8
Keep secrets out of the conversation
A secret is any value that grants access: API tokens, private keys, passwords, session keys. The safest prompt contains file paths and variable names, never values.
Temporary files, when an agent needs direct access
- One file per secret with a clear name, such as
~/Desktop/replicate-api-token.txt. Only the value goes in. - Restrict it with
chmod 600 ~/Desktop/replicate-api-token.txt. - Give the path and the rule. “Read this file only when needed. Never print, echo, log, screenshot, commit or paste its contents.”
- Make the agent put values in the right place. Local values in an ignored
.env.local. Production values in Coolify's encrypted variables. Server-side only. - Verify, then delete the files and empty the Trash. Deletion reduces exposure. It does not make a leaked token safe. Rotate anything exposed.
The two-file environment pattern
.env.example is safe to commit because it holds names and fake placeholders. .env.local holds real values and stays ignored. Never prefix a server secret with NEXT_PUBLIC_. Next.js ships those to the browser.
# Commit this file with names and fake placeholders only REPLICATE_API_TOKEN= REPLICATE_MODEL=owner/model-name AUTH_SECRET= APP_PASSWORD_HASH= DATABASE_PATH=/app/data/app.db # Keep real local values here (never commit) # .env.local # .gitignore must include .env* !.env.example
6 of 8
Customise one prompt, then let the agent work
This one builds a private, mobile-first AI calorie tracker. Change the product if you like. Keep the infrastructure and safety sections.
Build and deploy a private, mobile-first AI calorie tracker. Continue through implementation, deployment and live verification. Do not stop after planning, scaffolding or a local build. PROJECT VALUES - App name: APP_NAME - Local working folder: LOCAL_PATH - GitHub owner/repository: GITHUB_OWNER/REPO_NAME - Production domain: DOMAIN - Coolify URL: COOLIFY_URL - Coolify API token file: COOLIFY_TOKEN_FILE_PATH - Replicate token file: REPLICATE_TOKEN_FILE_PATH - Single-user login secret or password-hash file: AUTH_SECRET_FILE_PATH - Preferred Replicate model: REPLICATE_MODEL (confirm its current official model page and API schema before coding) NON-NEGOTIABLE SAFETY 1. Treat every token and password as secret. Read the named files only when required. Never print, echo, log, screenshot, paste into chat, include in command output, or commit their contents. 2. Use obvious fake placeholders in .env.example. Put real local values in .env.local, confirm it is ignored, and put production values in Coolify's encrypted environment variables. 3. Keep every Replicate call server-side. Never use NEXT_PUBLIC_ for a secret and never send the Replicate token to the browser. 4. Use official current documentation for Next.js, Coolify and Replicate APIs. Do not rely on remembered endpoints or stale examples. 5. Before pushing, inspect the staged diff and repository history for secret-shaped values. If a secret is exposed, stop, tell me which credential needs rotation without repeating it, rotate it, then continue. BUILD THE APP 1. Inspect LOCAL_PATH first. Reuse any existing app, repository, branch, components and deployment configuration. Do not create a duplicate repository or second app resource. 2. Use the current stable Next.js App Router with TypeScript. Keep the dependency list small and use the repository's existing package manager. 3. Build a fast, installable PWA with a web app manifest, app icons and a clear offline state. It must work at 320px wide, with 44px tap targets, safe-area spacing, strong focus states, reduced-motion support and no horizontal overflow. 4. Add single-user authentication with a secure password hash, an HttpOnly Secure SameSite cookie, session expiry, logout, rate limiting on login and protected app/API routes. Do not store a plaintext password. 5. Store meals, food items, estimated calories, protein/carbs/fat, notes, timestamps and AI-request status in SQLite. Add explicit migrations and a documented migration command. 6. Mount SQLite under one configurable data directory such as /app/data. Run exactly one application replica. SQLite must live on a persistent Coolify volume and survive container replacement. 7. Let the user type or photograph a meal. Send the request from a protected server route to REPLICATE_MODEL, validate the model output, show the estimate as editable before saving, and handle timeouts, invalid output and model errors without losing the user's input. 8. Add daily totals, recent meals, edit/delete, loading and empty states. Make the primary flow comfortable on a phone. 9. Add GET /api/health. It must return a small non-secret JSON response and a non-200 status when the app cannot reach its database. Do not require authentication for this endpoint. 10. Add a production Dockerfile with an efficient multi-stage build, a non-root runtime user where practical, a small runtime image and a startup path that applies safe migrations before starting the app. 11. Add .env.example, .gitignore rules, a concise README and deployment notes covering the exact data volume path, internal port, health path, migration command and required environment-variable names. VERIFY BEFORE DEPLOYING 1. Add focused tests for authentication boundaries, health response, database persistence logic, model-output validation and the main mobile flow. Do not call the paid Replicate API in tests. 2. Run formatting, lint, TypeScript checking, tests and the production build. Fix every relevant failure. 3. Inspect at 320px, a common iPhone width, tablet and desktop. Fix overflow, contrast, focus order, touch targets and code or error text that breaks the layout. 4. Create or reuse the private GitHub repository GITHUB_OWNER/REPO_NAME. Commit logical changes and push the finished branch. Preserve concurrent work and do not force-push over other changes. DEPLOY WITH COOLIFY 1. Reuse the existing Coolify project/application when one already matches this repository and domain. Otherwise create one application connected to the private GitHub repository, using the GitHub App or a read-only deploy key. 2. Configure the production branch, Dockerfile build, internal port, DOMAIN, /api/health, and one replica. 3. Create a persistent volume whose container destination exactly matches the SQLite data directory. Confirm the database file is written there, not inside the replaceable container filesystem. 4. Add the required production environment variables from the named secret files without displaying their values. Mark sensitive values as secrets. 5. Make migrations run safely once during startup or as a controlled pre-deploy command. Never run two SQLite replicas against the same file. 6. Trigger the deployment. Watch build and runtime logs without exposing secrets. If the small host runs out of memory during builds, reduce build load, use a more efficient Docker build or add safe headroom/swap, then retry. 7. Wait for DNS and HTTPS, then verify the exact live URL. LIVE ACCEPTANCE CHECKS - DOMAIN serves valid HTTPS. - An unauthenticated visitor cannot see app data or call protected APIs. - Login and logout work, and the session cookie has secure production settings. - /api/health returns success without leaking configuration. - A test meal can be estimated through a server-side Replicate call, edited and saved. - The saved meal still exists after a redeploy/restart. - The interface works at 320px and a common iPhone width. - The GitHub repository is private, one app replica is running, the SQLite volume is mounted, and a backup method is documented. - No real secret exists in source, git history, screenshots, prompts or logs. Finish by reporting the live URL, deployed commit, checks run, Coolify resource used, volume destination, health result and any secret files I should now delete. Never include a secret value in the report.
7 of 8
Choose how Coolify gets configured
Both paths end in the same app. Use the dashboard if you want to see every setting. Use the API if you want the agent to keep going without you clicking.
Path A
Coolify UI
- One project and a production environment.
- Add the private repo via the GitHub App or deploy key.
- Select the branch and Dockerfile build. Set the internal port.
- Encrypted variables, one replica, the SQLite volume, a safe migration command.
- Set the HTTPS domain and
/api/health, deploy, read the logs.
Path B
Coolify API
Safe API handoff
Makes the no-print rule explicit and prevents duplicate resources. Coolify uses a Bearer token and the /api/v1 base URL.
Use the existing Coolify instance and deploy the existing private GitHub repository. Do not create duplicate projects, applications or repositories. - Coolify URL: COOLIFY_URL - Coolify API token file: COOLIFY_TOKEN_FILE_PATH - Server/project/environment IDs if known: COOLIFY_IDS_OR_UNKNOWN - GitHub repository and branch: GITHUB_OWNER/REPO_NAME, BRANCH - Production domain: DOMAIN - Required environment variable names: ENV_VAR_NAMES_ONLY - Secret file paths: SECRET_FILE_PATHS - SQLite container directory: SQLITE_DATA_DIRECTORY - Health endpoint: /api/health Read secrets only from the exact files above. Never print, echo, log, screenshot, commit or paste their contents into chat. Use the narrowest Coolify token permissions that can complete the job. Inspect existing resources first, configure one replica and a persistent volume, set encrypted environment variables, deploy, wait for healthy HTTPS, verify auth and persistence across one redeploy, then report IDs and results without secret values.
For the next update
The shorter prompt, once the app exists. It says that “pushed” is not the finish line.
Deploy the current app update all the way to production. App folder: LOCAL_PATH Repository: GITHUB_OWNER/REPO_NAME Domain: DOMAIN Coolify URL: COOLIFY_URL Coolify token file: COOLIFY_TOKEN_FILE_PATH Inspect the existing branch, GitHub repository and Coolify resource first. Reuse them; do not create duplicates. Preserve concurrent changes. Read the token file only when needed and never print, log, commit or paste its contents. Use current official docs for any API that may have changed. Run lint, typecheck, tests and the production build. Confirm migrations are safe, SQLite remains on its persistent volume with exactly one replica, and secrets stay server-side. Commit and push the finished update, trigger or wait for the existing Coolify deployment, then verify HTTPS, auth, /api/health, the changed feature and persistence on DOMAIN. Do not stop at a plan, local build or successful push. Report the live commit and verification results without secret values.
If the deploy fails
8 of 8
Prove it survives real life
A green badge is one signal. The app is finished when privacy, AI calls, phone UX and persistence all work on the public URL.
- The repo is private and the deployed commit matches the intended branch.
- The domain has valid HTTPS with no warning.
- An unauthenticated visitor cannot see data or call protected APIs. Login and logout work.
/api/healthreturns 200 with no configuration or secret values.- A meal goes to Replicate only from a protected server route, can be edited, and saves.
- The saved meal is still there after a restart or redeploy. One replica, mounted volume.
- The app works at 320px, iPhone width, tablet and desktop, with visible keyboard focus.
- Coolify settings and app data have backups, and the restore path has been tested or written down.
- Temporary files are deleted. Anything shown in chat, logs, screenshots or Git is rotated.
Docs used for this guide
Want the app built with you?
I build small AI products and the deployment behind them, then write down the parts worth reusing.
