Empower your software hosting it on a VPS (Virtual Private Server). Cheaper and portable.
If you want to replicate your localhost to staging/production, you can use this guide.
Self-hosted TypeScript apps I'm using:
- [Web] Vite React (<www.yourdomain.com>)
- [Server] NodeJS (api.yourdomain.com)
Self-hosted services I'm using:
- [VPS] Hetzner
- [Git] GitHub
- [Deployment] Coolify
- [Database] Postgres
- [Local-Cloud Sync] PowerSync
- [Auth] Supertokens
Other services:
- [Reverse Proxy] Traefik (configured in Coolify)
- [DNS, TLS, Protection] Cloudflare
- [Email] Docker Inbucket for local development (not VPS)
- [Postgres Migration] Flyway
For Postgres migration, I'm using Flyway.
- 0. Pre-requisites
- 1. Create The Services Locally
- 2. Setup VPS
- 3. Setup DNS & TLS
- 4. Setup Coolify
- 5. Deploy the Services to the VPS
- [Local] Install on your laptop Deno
- [Local] Install on your laptop Docker Desktop or other, like OrbStack.
- [Local] Configure
.env
files for your services (seeservices/postgres/.env
for example) - Your domain connected to Cloudflare.
The local development environment uses Docker Compose to run multiple services. Each service is defined in its own directory under services/
with its configuration files. The services include:
- Postgres: Main database for the application
- PowerSync: Data synchronization service with MongoDB
- Supertokens: Authentication service
- Email: Local email testing with Inbucket
All services are managed through Deno tasks for consistent command execution:
# Important: Run all commands from the root directory of the project
# cd scripts/services
# Start all services
deno task docker:up
# Start specific services
deno task docker:up postgres
deno task docker:up email powersync
# Stop all services
deno task docker:down
# Restart services
deno task docker:restart
# Clean volumes
deno task docker:clean # Clean all volumes
deno task docker:clean postgres # Clean specific service volumes
# Setup PowerSync (usually automatic)
deno task docker:setup_powersync
Services are defined in scripts/services/types.ts
:
email
postgres
powersync
supertokens
- Services start in a specific order to handle dependencies
- When starting
postgres
, PowerSync setup runs automatically - All commands are idempotent - safe to run multiple times
- Health checks run automatically to verify service status
- Create VPS on Hetzner (cheaper than AWS; link 2. link 2). Debian.
- Connect to your Hetzner VPS with SSH. Guide https://docs.hetzner.com/cloud/servers/getting-started/connecting-to-the-server/
- Update and upgrade Debian packages.
sudo apt update && sudo apt upgrade -y
[!CAUTION] Work in progress
- Enable TLS Strict mode on Cloudflare https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/full-strict/
- Create a Cloudflare Origin CA https://developers.cloudflare.com/ssl/origin-configuration/origin-ca/
- Setup a DNS record for your domain pointing to your VPS.
- Obtain API Token from Cloudflare and update Traefik .env
Use cloud or self-hosted. I'm using the cloud (only $5/month).
-
Create a Coolify account.
-
Create a new server in an Staging or Production environment. My case is Staging.
-
Create a SSH key automatically with the "Generate new Ed25519 SSH key" function.
To allow Coolify to connect to your VPS, you need to create a SSH key. I prefer to use a different one than my laptop (in step #1).
-
I'm using the root user automatically created by the VPS. Note that this is not recommended for production. Coolify has a beta feature to allow other users.
-
Create a source with GitHub Apps to connect Coolify to your repository.
-
Create a new resource on Coolify via the source you created in the previous step (GitHub Apps).
-
Select (Docker Compose instead of Nixpacks). Remember to write the branch you want to deploy.
-
Check
.env.example
of this repoEnvironment Variables
of the resource -->Production
. Add the missing variables to Coolify. -
Create Docker network (found in
docker-compose.yaml
files) in the VPS using SSH terminal. This is to allow the services to communicate with each other.docker network create backend_network
-
Deploy the service.
-
Do this for each service (PowerSync, Supertokens, Postgres).
- Check Docker logs:
docker logs <container_name>
- Verify environment variables in service
.env
files - Use
deno task docker:down
followed bydeno task docker:up
to reset services - Clean volumes if database issues occur:
deno task docker:clean
- Check Coolify logs for deployment issues
- Verify network configuration
- Ensure all environment variables are set correctly
- Check Cloudflare DNS and SSL/TLS settings
- Web and server sample apps.
- Add Traefik for reverse proxy to Coolify.