name: lovable-vps-documents-deploy
description: Deploy Lovable/TanStack Start app to VPS — Documents app (DocCorretor) on VPS /var/www/documentos2/
category: devops
Lovable → VPS Documents App Deployment (UPDATED)
Context
Lovable/TanStack Start app deploying to VPS at documentos.rochasalesseguros.com.br. Supabase project: dauftiqcvgaydddoxqhh (different from ComercialRS which is nzaxsorgsecnmqwufawn).
⚠️ CRITICAL: Management API Blocked
The Management API (api.supabase.com) is blocked by Cloudflare on this VPS. Migrations must be done manually via Supabase Dashboard SQL Editor — Supabase CLI and Management API calls will fail.
Deployment Steps
1. Source Files
Two zips available on VPS in /tmp/:
- -
deploy-vps-nodejs_1.zip— complete deploy package - -
migrations-dashboard.zip— SQL migrations (consolidated + individual) - -
dist/server/server.js— SSR handler (NOT an HTTP server) - -
dist/client/— static assets - - URL: https://documentos.rochasalesseguros.com.br
- - VPS: 31.97.243.106, SSH: root / Marcia19671951@
- - Work dir: /var/www/documentos2/
- - Supabase (Documents):
dauftiqcvgaydddoxqhh - - Supabase URL: https://dauftiqcvgaydddoxqhh.supabase.co
- - Anon Key: eyJ_REDACTED
- - Service Role: eyJ_REDACTED
- - Service:
systemctl restart documentos2
2. Extract and Fix
`bash
Extract (zip has 'deploy-vps-nodejs/app/' structure → goes to /var/www/documentos2/app/)
python3 -c "
import zipfile, os
z = zipfile.ZipFile('/tmp/deploy-vps-nodejs_1.zip')
for name in z.namelist():
if name.startswith('deploy-vps-nodejs/'):
new_name = name[len('deploy-vps-nodejs/'):]
else:
new_name = name
if not new_name: continue
target = os.path.join('/var/www/documentos2', new_name)
if name.endswith('/'):
os.makedirs(target, exist_ok=True)
else:
os.makedirs(os.path.dirname(target), exist_ok=True)
with open(target, 'wb') as f:
f.write(z.read(name))
"
Copy app-level files to root (zip keeps app/ subdirectory)
cp -f /var/www/documentos2/app/vite.config.ts /var/www/documentos2/vite.config.ts
cp -f /var/www/documentos2/app/package.json /var/www/documentos2/package.json
cp -f /var/www/documentos2/app/tsconfig.json /var/www/documentos2/tsconfig.json
cp -rf /var/www/documentos2/app/src /var/www/documentos2/src
cp -rf /var/www/documentos2/app/supabase /var/www/documentos2/supabase
Preserve the CORRECT .env (dauftiqcvgaydddoxqhh) from root level
The app/.env has the WRONG supabase project — do NOT use it
`
3. Verify/Correct vite.config.ts
If it imports @lovable.dev/vite-tanstack-config → REPLACE with standard config:
`ts
import { defineConfig } from "vite";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import viteReact from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import tsConfigPaths from "vite-tsconfig-paths";
export default defineConfig({
server: { host: "0.0.0.0", port: 3000 },
plugins: [
tsConfigPaths(),
tailwindcss(),
tanstackStart({ target: "node-server" }),
viteReact(),
],
});
`
4. Run Migrations (MANUAL via Dashboard)
⚠️ Management API blocked → use Dashboard:
1. https://supabase.com/dashboard/project/dauftiqcvgaydddoxqhh/sql
2. New Query → paste 00_full_schema_consolidated.sql (from migrations-dashboard.zip) → Run
3. Storage: create buckets manually:
- documents (Private)
- cms-media (Public)
4. Trigger (if not auto-created):
`sql
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
`
5. Build
`bash
cd /var/www/documentos2
source ~/.nvm/nvm.sh && nvm use 20
npm install
npm run build
`
6. Output Structure (CRITICAL)
TanStack Start target: "node-server" outputs to dist/ NOT .output/:
7. server.js HTTP Wrapper
Create /var/www/documentos2/server.js:
`javascript
import { createServer } from 'node:http';
import { createReadStream } from 'node:fs';
import { join, dirname, extname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createHandler } from './dist/server/server.js';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PORT = process.env.PORT || 3011;
const CLIENT_DIR = join(__dirname, 'dist', 'client');
const handler = createHandler({ single: true });
const mimeTypes = {
'.html': 'text/html',
'.js': 'application/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon',
};
createServer((req, res) => {
const url = req.url.split('?')[0];
if (req.url.startsWith('/api/') || req.url === '/' || !extname(url)) {
handler(req, res);
return;
}
const filePath = join(CLIENT_DIR, url);
const ext = extname(filePath);
const ct = mimeTypes[ext] || 'application/octet-stream';
res.writeHead(200, { 'Content-Type': ct });
createReadStream(filePath).pipe(res);
}).listen(PORT, '0.0.0.0', () => {
console.log(Server on port ${PORT});
});
`
8. Systemd Service
`ini
[Unit]
Description=DocCorretor App v2
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/documentos2
EnvironmentFile=/var/www/documentos2/.env
ExecStart=/usr/bin/node /var/www/documentos2/server.js
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
`
`bash
Create /etc/systemd/system/documentos2.service
systemctl daemon-reload && systemctl enable --now documentos2
`
9. Nginx
`nginx
server {
listen 80;
server_name documentos.rochasalesseguros.com.br;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:3011;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
`
`bash
Create /etc/nginx/sites-available/documentos2
ln -sf /etc/nginx/sites-available/documentos2 /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d documentos.rochasalesseguros.com.br
`
Root Cause — Previous Attempt (Blank Screen)
1. @lovable.dev/vite-tanstack-config not on npm → npm install or build failed silently
2. TSR manifest (_tanstack-start-manifest_*.js) was 404 → router couldn't initialize
3. $_TSR.h() never called → React never hydrated → blank page
4. Main bundle loaded (HTTP 200) but crashed before importing lazy chunks → auth_.js and Combination_.js never requested
Key Corrections Applied
| Issue | Old | New |
| ------- | ----- | ----- |
| Output dir | .output/ | dist/ |
| App root | /var/www/documentos/ | /var/www/documentos2/ |
| Port | 3010 | 3011 |
| Vite config | @lovable.dev/vite-tanstack-config | explicit TanStack plugins |
| Supabase | nzaxsorgsecnmqwufawn | dauftiqcvgaydddoxqhh |