Skip to content

Deploy a web app (frontend + backend)

Run frontend and backend containers behind an internal proxy, with the platform edge handling HTTPS.

Web app deployment - frontend, backend, and an internal reverse proxy

What you'll run

A frontend container, a backend container, and a database -- all on one instance. An optional Caddy container runs on port 8080 inside the instance and routes between them. The node edge terminates HTTPS and forwards to that port.

Before you start

  • An instance (a docker capability profile if you want Docker Compose).
  • Your app and frontend images pushed to a registry.
  • No domain needed: every instance gets an HTTPS URL automatically. A custom domain is optional.

Project structure

paths
mkdir -p ~/apps/myapp
~/apps/myapp/docker-compose.yml
~/apps/myapp/Caddyfile

docker-compose.yml

The proxy publishes only 8080 inside the instance. The node edge owns the public 80/443, so there is no need to map those ports here.

yaml
services:
proxy:
image: caddy:2
restart: unless-stopped
ports: ["8080:8080"]
volumes: ["./Caddyfile:/etc/caddy/Caddyfile:ro", "caddy_data:/data"]
depends_on: [frontend, backend]
frontend:
image: ghcr.io/yourorg/frontend:latest
restart: unless-stopped
backend:
image: ghcr.io/yourorg/backend:latest
restart: unless-stopped
environment: { DATABASE_URL: "postgresql://user:pass@db:5432/app" }
db:
image: postgres:16-alpine
volumes: ["pg_data:/var/lib/postgresql/data"]
environment: { POSTGRES_DB: app, POSTGRES_USER: user, POSTGRES_PASSWORD: pass }
volumes: { caddy_data: {}, pg_data: {} }

Caddyfile

This Caddy listens on :8080 and does plain HTTP. TLS is handled by the platform edge, not by this container.

text
:8080 {
encode gzip
handle /api/* {
reverse_proxy backend:3000
}
handle {
reverse_proxy frontend:3000
}
}

Launch

bash
$ cd ~/apps/myapp
$ docker compose up -d --build

Point the platform at your proxy

In the dashboard, open the instance's Networking tab, set the web site origin port to 8080, and save. Open the HTTPS URL shown there.

bash
$ curl -s http://127.0.0.1:8080/health # inside the instance
$ curl -s https://<hostname>.nairacloud.xyz/health
$ # If .nairacloud.xyz is not resolving yet:
$ curl -s https://<node-ip>.<hostname>.sslip.io/health

Use your own domain

Add an A record for your domain pointing at the node IP, then attach it under Custom domain in the same Networking tab. The platform issues TLS for the new name; the guest proxy does not need any certificate configuration.

Practical -- try it now

Your web app in 5 minutes

  1. Provision an instance, SSH in, and run the commands above.
  2. In Sites, set the web origin to 8080.
  3. Open the HTTPS URL from the dashboard -- no DNS record needed for the platform name.
  4. Optional: point your own domain at the node IP and attach it for a branded URL.
Ask a question...
Ctrl+I