Self-hosted (Coolify)
Deploy Launchy to your own VPS using Coolify — Postgres + Redis managed for you, auto HTTPS, one-click updates.
Coolify is an open-source, self-hostable PaaS — think Heroku on your own VPS. Launchy deploys to it cleanly with Postgres + Redis managed by Coolify, automatic TLS, and a scheduled-task runner for the crons.
This guide assumes you already have Coolify installed on a VPS. If not, follow Coolify's install guide first — one command on a fresh Ubuntu host.
1. Connect your private repo to Coolify
You'll be deploying from the private launchy-customers/launchy-template repo. Coolify needs GitHub access.
- Coolify dashboard → Sources → + Add → GitHub App
- Install the Coolify GitHub App on your account
- Grant access to the
launchy-templaterepo
2. Provision Postgres and Redis via Coolify
Create these before the app — the app needs their connection strings.
Postgres
- Coolify → your server → + New Resource → Database → PostgreSQL 16
- Name:
launchy-postgres - Note the credentials (user, password, database name) Coolify generates
- Start the database
Coolify exposes the DB on an internal network. The connection string will look like:
postgresql://<user>:<pass>@launchy-postgres:5432/<db>Redis
- + New Resource → Database → Redis 7
- Name:
launchy-redis - Set a password
- Start
Internal host: launchy-redis, port 6379.
3. Create the Launchy application
- + New Resource → Application
- Source: pick the GitHub App you connected
- Repository:
launchy-customers/launchy-template - Branch:
main - Build pack:
Nixpacks(auto-detects Next.js + Bun) ORDockerfileif you prefer to bundle one - Port:
3000 - Click Deploy (it'll fail on first try — that's expected, we still need env vars)
4. Configure environment variables
In the application view → Environment Variables tab, paste (fill in real values):
DATABASE_URL=postgresql://<user>:<pass>@launchy-postgres:5432/<db>
BETTER_AUTH_SECRET=<openssl rand -base64 32>
BETTER_AUTH_URL=https://your-domain.com
REDIS_HOST=launchy-redis
REDIS_PORT=6379
REDIS_PASSWORD=<your redis password>
REDIS_DB=0
CRON_SECRET=<openssl rand -base64 32>Add other integrations as needed — Stripe, Plunk, R2, Turnstile, Discord, OAuth. See Environment Variables for the full reference.
Click Save.
5. Attach the domain
- Coolify app → Domains tab → add
your-domain.com - Point your DNS A record to the VPS IP
- Coolify auto-issues a Let's Encrypt cert within a minute
- Update
BETTER_AUTH_URLto match the finalhttps://your-domain.comif you haven't yet
6. First deploy
- Coolify app → Deploy button
- Watch the live logs — build takes 2-5 minutes depending on VPS
- On success: visit
https://your-domain.com
The site will 500 on first visit because the database schema isn't pushed yet. Fix next.
7. Push the database schema
You need to run bun db:push once against the production database. Use Coolify's built-in terminal:
- Coolify → your application resource (Launchy, not the Postgres resource) → Terminal tab
- Run:
bun run db:push
The command applies the Drizzle schema using your DATABASE_URL env var (already set in step 4).
If you prefer to run from your laptop instead: expose the Postgres port publicly in the database resource, then:
DATABASE_URL="postgresql://...public-endpoint..." bun run db:pushEither way, reload the site — it loads properly.
8. Create the first admin
Sign up at /sign-up on your live site, verify your email, then use Coolify's database terminal:
- Coolify →
launchy-postgres→ Terminal tab psql -U <user> -d <db>UPDATE "user" SET role = 'admin' WHERE email = '[email protected]';
Refresh — the /admin link appears.
9. Configure crons via Coolify Scheduled Tasks
Coolify has a built-in cron runner on each application. Two tasks to add:
- Coolify app → Scheduled Tasks tab → + Add
- Task 1: weekly-batch
- Name:
Weekly batch - Frequency:
0 6 * * 1(Monday 06:00 UTC — adjust to match yourlaunch_day+launch_hour_utcsettings) - Command:
curl -sS -X POST -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/weekly-batch
- Name:
- Task 2: cleanup-highlights
- Name:
Cleanup highlights - Frequency:
0 * * * *(every hour) - Command:
curl -sS -X POST -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/cleanup-highlights
- Name:
Coolify injects environment variables into the scheduled task context, so $CRON_SECRET resolves.
Save each task. The status badge shows when they last ran and if they succeeded.
10. Post-deploy checklist
- Homepage loads without errors
- Sign-up → email verification works (if Plunk is configured — otherwise check server logs for the link)
-
/adminaccessible after SQL promote -
/admin/settingssaves persist across page reload - Trigger the weekly cron manually from Scheduled Tasks → Run Now; check response logs
- Upload a thumbnail from
/submit; verify R2 (or Coolify's volume fallback) serves it back - If using Stripe: fire a test webhook via Stripe CLI pointing at
https://your-domain.com/api/stripe/webhook
Updates
When you git push to main, Coolify redeploys automatically (if auto-deploy is on). Otherwise:
- Coolify app → Deploy
Schema changes require running bun db:push again in the terminal after deploy.
Backups
Postgres
Coolify has built-in database backups on the Postgres resource:
launchy-postgres→ Backups tab- Enable scheduled backups (e.g., daily)
- Coolify stores them locally on the VPS; push to S3 for off-site:
- Backups → S3 — configure bucket + credentials
R2
If you're using Cloudflare R2 for uploads, enable versioning in R2 bucket settings. R2 keeps overwrites for 30 days by default.
Monitoring
Coolify shows:
- Deployment logs per resource
- Live logs (stdout tail) on the app view
- Resource usage (CPU, memory, disk)
For external uptime: add an uptimerobot.com monitor hitting https://your-domain.com.
Resource sizing
A $5-$10/month VPS (1-2 GB RAM) comfortably runs Launchy + Postgres + Redis + Coolify overhead for any new directory. Scale up when you hit 100k monthly visitors.
Common issues
App container keeps restarting — Check Logs. Usually a missing required env var (the app throws at startup if validation fails).
DATABASE_URL connection refused — launchy-postgres host isn't resolving. Coolify internal DNS requires both resources to be on the same Coolify server. Cross-server connections need public ports or a Coolify network bridge.
Scheduled tasks never fire — Verify the task is enabled (toggle on) and the frequency is valid cron syntax. Coolify shows the next-run time — if it's "never", the cron string is invalid.
"TLS handshake failed" — DNS A record not propagated yet. Wait 5-60 min after pointing DNS. Retry the domain issuance from the Domains tab.
Uploads vanish after redeploy — The app container is ephemeral. Either use Cloudflare R2 (recommended) or add a Coolify Persistent Storage volume mounted to /app/public/uploads/.