spomeni/coolify.md
2026-06-20 19:28:05 +02:00

334 lines
11 KiB
Markdown

# Deploying SpomeniQR on Coolify
This guide covers deploying SpomeniQR to a VPS using [Coolify](https://coolify.io/) — a self-hosting platform similar to Heroku/Vercel that manages Docker deployments, SSL, and databases.
## Prerequisites
- A VPS with Docker installed (Coolify handles this)
- Coolify installed on your VPS (see [coolify.io/docs](https://coolify.io/docs/installation))
- Domain `testbed.mk` with DNS configured:
- **A record** `@` → your VPS IP
- **A record** `*` → your VPS IP (wildcard for subdomains)
- A Contabo S3 bucket set up with public read policy
## Architecture Overview
Coolify will run two containers:
1. **app** — Next.js standalone build (Dockerfile)
2. **db** — PostgreSQL 16 (Coolify managed database)
We do **not** deploy Nginx via Docker — Coolify has its own reverse proxy (Traefik/Caddy) that handles SSL, subdomain routing, and the `X-Subdomain` header.
```
Internet
├── *.testbed.mk ──► Coolify Proxy (:80/:443)
│ ├── Extracts subdomain → sets X-Subdomain header
│ └── Proxies to app:3000
└── testbed.mk ──► Coolify Proxy ──► app:3000
```
## Step 1: Add a New Project in Coolify
1. Open your Coolify dashboard
2. Click **+ Add New Project**
3. Name it `SpomeniQR`
## Step 2: Create the Database
1. Inside the project, click **+ Add New Resource** → **Database**
2. Select **PostgreSQL**
3. Configure:
- **Name:** `spomeniqr-db`
- **PostgreSQL Version:** 16
- **Database Name:** `monuments`
- **Username:** `postgres`
- **Password:** generate a strong password or set your own
4. Click **Deploy**
5. After deployment, note the **Internal Connection String** — it looks like:
```
postgresql://postgres:YOUR_PASSWORD@spomeniqr-db:5432/monuments
```
You'll need this for `DATABASE_URL`.
## Step 3: Add the Application
1. Inside the project, click **+ Add New Resource** → **Application**
2. Select **Public Repository** (or **Private** if your repo is private)
3. Configure:
- **Name:** `spomeniqr`
- **Repository URL:** your Git repo URL
- **Branch:** `main`
- **Build Pack:** **Nixpacks** (auto-detected) or **Docker** (uses the Dockerfile)
### Option A: Nixpacks (Recommended — simpler)
Leave the build pack as **Nixpacks**. Coolify will auto-detect Next.js and build it.
Add these **Build Commands:**
```
npx prisma generate && npm run build
```
Add this **Start Command:**
```
npx prisma migrate deploy && node .next/standalone/server.js
```
### Option B: Docker (uses the project's Dockerfile)
Set **Build Pack** to **Docker**. Coolify will use the `Dockerfile` in the repo root. No additional configuration needed — it already includes Prisma migration and standalone server startup.
**Note:** If using Docker build pack, the `DATABASE_URL` must use `spomeniqr-db` as the host (Coolify internal network), not `localhost`.
## Step 4: Configure Environment Variables
In the application settings, go to **Environment Variables** and add:
```env
# Database — use the Coolify internal connection string
DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@spomeniqr-db:5432/monuments
# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_...
CLERK_SECRET_KEY=sk_live_...
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL=/
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL=/
# Contabo S3
S3_ENDPOINT=https://eu2.contabostorage.com
S3_REGION=eu-2
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_BUCKET_NAME=monuments-images
# App
NEXT_PUBLIC_APP_URL=https://testbed.mk
NEXT_PUBLIC_APP_DOMAIN=testbed.mk
# Node
NODE_ENV=production
```
**Important:**
- `DATABASE_URL` must point to the Coolify **internal** hostname (`spomeniqr-db`), not `localhost`.
- Use your **production** Clerk keys (`pk_live_` / `sk_live_`), not the test ones.
## Step 5: Configure Domain & Subdomain Routing
### Set the Main Domain
1. In the application settings, go to **Configuration****Domains**
2. Add: `testbed.mk`
3. Enable **HTTPS** — Coolify will auto-provision a Let's Encrypt certificate
### Enable Wildcard Subdomain Routing
This is the critical part. Coolify's proxy needs to:
1. Accept requests for `*.testbed.mk`
2. Extract the subdomain and pass it as the `X-Subdomain` header to the Next.js app
#### Option A: Coolify Proxy Configuration (Recommended)
1. In your application, go to **Configuration****Domains**
2. Add both domains:
- `testbed.mk`
- `*.testbed.mk`
3. Coolify will request a wildcard SSL certificate. If your DNS provider supports DNS-01 challenges (Cloudflare, Route53, etc.), this works automatically. Otherwise, you may need to add each subdomain manually.
#### Option B: Custom Proxy Configuration
If Coolify doesn't support wildcard domains easily, add a **custom Caddy/Traefik configuration** in the Coolify settings:
For **Caddy** (Coolify's default proxy):
Create a file at `/data/coolify/proxy/caddy/custom/testbed.mk`:
```
*.testbed.mk {
reverse_proxy app:3000 {
header_up X-Subdomain {http.request.host.labels.2}
header_up X-Forwarded-Proto {scheme}
}
}
testbed.mk {
reverse_proxy app:3000 {
header_up X-Forwarded-Proto {scheme}
}
}
```
For **Traefik** (alternative proxy), you'd add labels to the container:
```yaml
traefik.http.routers.spomeniqr.rule: HostRegexp(`{subdomain:[a-z0-9-]+}.testbed.mk`) || Host(`testbed.mk`)
traefik.http.middlewares.spomeniqr-subdomain.headers.customrequestheaders.X-Subdomain:
```
> **Note:** The proxy configuration varies based on your Coolify version and proxy choice. Check the Coolify docs for the latest instructions on wildcard domains.
## Step 6: Configure Clerk
1. Go to [Clerk Dashboard](https://dashboard.clerk.com)
2. Switch to your **Production** instance
3. Under **Paths**, set:
- Sign-in: `/sign-in`
- Sign-up: `/sign-up`
4. Under **Domains**, add:
- `testbed.mk`
- `*.testbed.mk`
## Step 7: Configure Contabo S3
1. Log into Contabo Object Storage
2. Create a bucket named `monuments-images` in region `eu-2`
3. Set the **bucket policy** for public read:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": { "AWS": ["*"] },
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::monuments-images/*"]
}
]
}
```
4. Set **CORS** to allow uploads:
```json
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST"],
"AllowedOrigins": ["https://testbed.mk", "https://*.testbed.mk"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3600
}
]
```
5. Create an API key with read/write permissions
## Step 8: Deploy
1. Click **Deploy** in the Coolify dashboard
2. Watch the build logs — it should:
- Install dependencies
- Run `npx prisma generate`
- Build the Next.js app
- Run `npx prisma migrate deploy`
- Start the server on port 3000
3. Once deployed, visit `https://testbed.mk` to verify
## Step 9: Verify Subdomain Routing
Test that wildcard subdomains work:
1. Create a memorial page with subdomain `test-memorial`
2. Visit `https://test-memorial.testbed.mk`
3. Check browser DevTools network tab — the `X-Subdomain` header should be set by the proxy
4. The Next.js middleware reads `X-Subdomain` and rewrites to the correct page
If subdomains aren't working:
- Check DNS: `dig *.testbed.mk +short` should return your VPS IP
- Check Coolify proxy logs for the wildcard domain configuration
- Verify the `X-Subdomain` header is being set in the proxy config
## Step 10: Verify Everything
```bash
# App health
curl -s https://testbed.mk | head -5
# Subdomain routing
curl -sI https://test-memorial.testbed.mk | head -5
# API health
curl -s https://testbed.mk/api/check-subdomain?slug=test | python3 -m json.tool
# Database connection (from Coolify terminal)
docker exec spomeniqr-app npx prisma db push --accept-data-loss
```
## Troubleshooting
### Build fails with Prisma errors
Make sure `DATABASE_URL` points to the Coolify internal hostname (e.g., `spomeniqr-db:5432`), not `localhost`. The app and database must be on the same Coolify network.
### Images return 401 from S3
Make sure you've applied the bucket policy for public read. See Step 7. If Contabo doesn't serve public objects via URL, the app uses an `/api/image?key=...` proxy route as a fallback.
### Subdomain routing not working
- Verify DNS wildcard `*.testbed.mk` points to your VPS
- Check that Coolify's proxy config includes both `testbed.mk` and `*.testbed.mk`
- Check the proxy access logs — the `X-Subdomain` header should appear
- If using a custom Caddyfile, make sure it's in the right directory and reload the proxy
### Clerk authentication issues
- Ensure production Clerk keys are set (not `pk_test_` / `sk_test_`)
- Verify `testbed.mk` and `*.testbed.mk` are added in Clerk dashboard domains
- Check that `NEXT_PUBLIC_APP_URL` and `NEXT_PUBLIC_APP_DOMAIN` are set correctly
### Database migration issues
If migrations fail on deploy, you can run them manually from the Coolify terminal:
```bash
# SSH into the app container
docker exec -it spomeniqr-app sh
# Run migrations
npx prisma migrate deploy
# Or push schema changes directly
npx prisma db push
```
## Environment Variables Reference
| Variable | Required | Description |
|----------|----------|-------------|
| `DATABASE_URL` | Yes | PostgreSQL connection string (Coolify internal) |
| `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` | Yes | Clerk publishable key (`pk_live_...`) |
| `CLERK_SECRET_KEY` | Yes | Clerk secret key (`sk_live_...`) |
| `NEXT_PUBLIC_CLERK_SIGN_IN_URL` | Yes | `/sign-in` |
| `NEXT_PUBLIC_CLERK_SIGN_UP_URL` | Yes | `/sign-up` |
| `S3_ENDPOINT` | Yes | Contabo S3 endpoint URL |
| `S3_REGION` | Yes | Contabo S3 region (e.g. `eu-2`) |
| `S3_ACCESS_KEY_ID` | Yes | S3 access key |
| `S3_SECRET_ACCESS_KEY` | Yes | S3 secret key |
| `S3_BUCKET_NAME` | Yes | S3 bucket name |
| `NEXT_PUBLIC_APP_URL` | Yes | `https://testbed.mk` |
| `NEXT_PUBLIC_APP_DOMAIN` | Yes | `testbed.mk` |
| `NODE_ENV` | Yes | `production` |
## Useful Coolify Commands
- **Redeploy:** Project → Application → Deploy
- **View Logs:** Project → Application → Logs
- **SSH into container:** Project → Application → Terminal
- **Database Management:** Project → Database → Admin (pgAdmin or Prisma Studio)
- **SSL Certificates:** Managed automatically by Coolify for configured domains
## Updates
To update the application:
1. Push changes to your Git repository
2. Coolify will auto-deploy if **Auto Deploy** is enabled, or click **Deploy** manually
3. The `start.sh` script runs `npx prisma migrate deploy` on every startup, so schema changes are applied automatically