How to host a Lovable app on a VPS with Coolify
To host a Lovable app on a VPS with Coolify, install Coolify on a Linux server, connect the GitHub repository through a GitHub App and pick a build: Nixpacks with static output in /dist, or a Dockerfile. Then add the VITE_ variables as build variables, point the domain with https:// and turn on deploy on push.
Heartscale’s recommendation: run the first deployment on a test subdomain and check sign-in, writes and refreshes on internal routes before you point the production domain. If the app has real users, payments or personal data, get the variables and secrets reviewed before you switch DNS.
This guide covers hosting only. If you still need to get the code and the database out of Lovable, start with How to leave Lovable and come back here for the server step.
What you need before you start
- A Linux VPS. Coolify needs 2 CPU cores, 2 GB of RAM and 10 GB of disk, with root or sudo SSH access (Coolify, Installation). The docs recommend a fresh server.
- A domain whose DNS you can edit.
- The code on GitHub. In Lovable, use Git sync under Project settings → Git (Lovable, GitHub).
- Your project’s stack. Open
package.json. If it lists@tanstack/react-start, it is TanStack Start and needs a running Node server. If not, it is React + Vite and the build outputs static files todist/(Lovable, Deploying outside Lovable).
Step 1: install Coolify
SSH into the VPS and run the official installer:
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
If Docker was installed through snap, remove it first. On Ubuntu, use an LTS release: 20.04, 22.04 or 24.04.
When it finishes, the terminal prints the dashboard link at http://<server-ip>:8000. Create the admin account right away. The docs warn that whoever reaches the registration page first becomes the instance admin and gets root access to the server.
Open the ports Coolify uses in your firewall (Coolify, Firewall):
| Port | Purpose |
|---|---|
| 22 | SSH |
| 80 | HTTP and certificate issuance |
| 443 | HTTPS |
| 8000 | Dashboard by IP |
| 6001 and 6002 | Real-time updates and web terminal by IP |
Once the dashboard runs on a domain, you can close 8000, 6001 and 6002.
Keep a copy of /data/coolify/source/.env. It holds the APP_KEY, which encrypts Coolify’s data and is required to restore the instance.
Step 2: connect GitHub through a GitHub App
The repository Lovable creates is private by default. For private repositories with push events, Coolify points to the GitHub App (Coolify, GitHub App):
- In the dashboard, open Sources and choose GitHub App.
- Name the source. Leave Organization empty if the repository is on your personal account.
- Click Register with GitHub, give the app a unique name on GitHub and confirm with Create GitHub App.
- Under Install repositories, pick Only select repositories and check only your app’s repository.
Granting access to a single repository limits what Coolify can see in your account.
Step 3: create the application
- Open the project and environment in Coolify and click + New.
- Choose Private Repository (with GitHub App).
- Select the server. On a self-hosted instance it shows up as localhost.
- Pick the source from step 2, then the repository, and click Load Repository.
- Choose the branch Lovable syncs, usually
main.
The next field is Build pack. It decides how the code becomes a site.
Step 4: choose the build
React + Vite with Nixpacks
This path adds the fewest files. Nixpacks detects the Node project and builds the image for you (Coolify, Nixpacks):
- Under Build pack, choose Nixpacks. Leave Base Directory at
/. - Under Output type, choose Static site and set Publish Directory to
/dist. - Keep port 80. The generated Nginx listens there.
- After creation, under General → Build pipeline → Site type, choose SPA.
- Check the Install Command, Build Command and Start Command fields under General. Override only what was detected wrong.
Lovable builds on Node 22. Nixpacks reads the version from engines.node in package.json, from .nvmrc, or from the NIXPACKS_NODE_VERSION variable.
React + Vite with a Dockerfile
Use this path if you want control over the image. Lovable suggests two stages: node:22-alpine to build and nginx:alpine to serve dist/ (Lovable, Deploying outside Lovable). An example in that shape:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_SUPABASE_URL
ARG VITE_SUPABASE_PUBLISHABLE_KEY
ARG VITE_SUPABASE_PROJECT_ID
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
And the nginx.conf next to it, with the SPA fallback:
server {
listen 80;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ /index.html;
}
}
In Coolify, choose Dockerfile under Build pack and set Ports Exposes to 80 (Coolify, Dockerfile). Coolify passes build variables as Docker build arguments, so the Dockerfile declares the ARG lines. Lovable notes it cannot run or test Docker builds, so test it yourself.
TanStack Start
Lovable projects created from May 13, 2026 use TanStack Start and need a running Node server. The build runs NITRO_PRESET=node-server npm run build, and the server starts with node .output/server/index.mjs on port 3000. In Coolify, set the internal port to 3000. The process must listen on 0.0.0.0 or the proxy cannot reach it, so set HOST=0.0.0.0. There is no SPA fallback here: the server handles routing.
Step 5: set the VITE_ variables
Variables with the VITE_ prefix are embedded at build time. In a Lovable project they are VITE_SUPABASE_URL, VITE_SUPABASE_PUBLISHABLE_KEY and VITE_SUPABASE_PROJECT_ID, with the values from the project’s .env.
In Coolify (Coolify, Environment variables):
- Open the application and click Environment Variables.
- Click Add, fill in Name and Value and save with Add variable. You can also paste the whole
.envin Developer view. - For
VITE_variables, keep Build time set to Available during build.
Changed a VITE_ value? Run a new deployment. Restart only applies runtime variables.
Anything with VITE_ ends up in every visitor’s browser. Payment, email or AI secrets never take that prefix. On TanStack Start, server function secrets stay as runtime variables, with Build time set to Not available during build.
In our reviews, before the first deployment, we list every variable and check whether any VITE_ one holds a secret. After the build, we search the files in dist/ for those values to confirm what reaches the browser.
Step 6: point the domain and turn on HTTPS
- In your DNS, point the hostname to the VPS IP. If you will use both
wwwand the bare domain, create both records. - In Coolify, open Domains and click Add domain.
- Under Protocol, choose
https. Under Domain, type the hostname, for exampleapp.yourdomain.com. - Add each hostname separately. To keep one as primary, use the www redirect option (Redirect to www or Redirect to non-www).
- Redeploy so the proxy applies the configuration.
With https:// and ports 80 and 443 open, the Coolify proxy requests and renews the certificate (Coolify, Domains).
Then go to your app’s auth settings and add the new URL to the allowed redirect URLs. Without it, sign-in breaks on the new domain.
Step 7: deploy on every push
Applications created through a GitHub App come with Auto deploy set to Deploy on push (webhooks) (Coolify, Auto deploy). If you see Manual deployments only, change it under Advanced → Deployment. Then push to the branch and confirm a deployment appears.
Lovable’s Git sync writes to the connected branch. So every change you make in the Lovable chat also goes live. If you want to review first, deploy manually, or point Coolify to another branch and merge changes through pull requests.
Step 8: test the SPA fallback
Open an internal route directly, for example /dashboard, and refresh. A 404 means the index.html fallback is missing.
With Nixpacks, go to General → Build pipeline → Custom Nginx configuration, add try_files $uri $uri/ /index.html; to the location / block and redeploy. A restart will not apply it, because the configuration is copied into the image during the build.
Run the other checks from Lovable’s docs too: sign in and out, then read, write and upload a file.
What becomes yours
Outside Lovable, you handle certificates, backups, access control, monitoring and security audits (Lovable, Deployment, hosting and ownership). Three Coolify points:
- Instance backup. Keep
/data/coolify/source/.envoff the server. The docs ask for a backup before every upgrade. - Updates. Under Settings → Updates, Automatic updates keeps Coolify current. It does not update the apps, databases or servers Coolify manages (Coolify, Upgrade).
- The old address. Your
lovable.appURL keeps serving the last version published there, and Publish only targets Lovable.
To weigh what this costs each month, read How much does it cost to keep a Lovable app online and our self-hosted deployment page.
Do it yourself or hire help?
If you already use SSH and DNS, the setup is the easy part. What weighs more is what you take on afterwards.
| Situation | Path |
|---|---|
| React + Vite project with no secrets in the front end, and someone on the team uses SSH and DNS | Do it yourself with this guide |
| Real users signing in with Google or another provider | Worth bringing in a team: the domain, HTTPS and redirect URLs have to switch together |
| Payment, email or AI secrets, or TanStack Start with server functions | Worth bringing in a team like ours: one mistake separating build and runtime variables puts the key in the browser |
| Nobody technical to maintain the server, backups and updates | Request a Heartscale diagnostic before you rent the VPS: it shows what your app uses from Lovable and what needs changes to run elsewhere |
Request a Heartscale diagnostic
Our team checks your app’s stack, sets up the build in Coolify, separates build variables from secrets and gets HTTPS, the domain and deploy on push working. Before that, the diagnostic shows what your app uses from Lovable and what needs changes to run elsewhere.
The launch-price diagnostic costs US$ 19 (was US$ 79) and is credited toward the deployment if you go ahead. We only work on apps whose owners can prove they own them.