VPS deployment conventions for Vera Sesiom using Dokploy as PaaS layer. Self-hosted alternative to AWS for simpler projects. Trigger: When deploying to a VPS, configuring Dokploy, setting up Docker-based deployments, or choosing a simpler hosting strategy.
.env files — NEVER hardcodedSee Infrastructure Decision Criteria for the full decision framework.
Quick reference:
| Choose VPS + Dokploy | Choose AWS |
|---|---|
| Predictable traffic | Spiky/unpredictable traffic |
| Fixed monthly budget | Pay-as-you-go acceptable |
| Simple architecture (web + API + DB) | Complex event-driven needs |
| Small team, no DevOps dedicated | DevOps capacity available |
| MVP or internal tool | Enterprise product |
| Fast time-to-deploy | Advanced services needed (ML, queues, etc.) |
| Provider | Best For | Starting Price |
|---|---|---|
| Hetzner | Best price/performance in EU | ~$4/mo |
| DigitalOcean | Simple UX, good docs | ~$6/mo |
| Contabo | Raw power for the price | ~$5/mo |
| Vultr | Global presence, good API | ~$6/mo |
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU |
| RAM | 4 GB | 8 GB |
| Storage | 80 GB SSD | 160 GB NVMe |
| Bandwidth | 20 TB/mo | Unlimited |
# 1. Update system
apt update && apt upgrade -y
# 2. Install Dokploy (one command)
curl -sSL https://dokploy.com/install.sh | sh
# 3. Access Dokploy panel
# https://your-server-ip:3000 (first time setup)
Dokploy Dashboard
├── Projects
│ ├── myapp-production
│ │ ├── web (Vue frontend — static/Nginx)
│ │ ├── api (Node.js backend)
│ │ ├── postgres (PostgreSQL database)
│ │ └── redis (Redis cache — if needed)
│ └── myapp-staging
│ ├── web
│ ├── api
│ ├── postgres
│ └── redis
Dokploy configuration:
| Setting | Value |
|---|---|
| Source | GitHub repo |
| Build method | Nixpacks or Dockerfile |
| Build command | pnpm --filter @vera-sesiom/web build |
| Publish directory | apps/web/dist |
| Domain | app.myproject.com |
Dockerfile (if not using Nixpacks):
# Build stage
FROM node:20-alpine AS builder
RUN corepack enable && corepack prepare pnpm@9 --activate
WORKDIR /app
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/web/package.json apps/web/
COPY packages/ packages/
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm --filter @vera-sesiom/web build
# Serve stage
FROM nginx:alpine
COPY --from=builder /app/apps/web/dist /usr/share/nginx/html
COPY apps/web/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
Dokploy configuration:
| Setting | Value |
|---|---|
| Source | GitHub repo |
| Build method | Dockerfile |
| Port | 3000 |
| Health check | GET /api/v1/health |
| Domain | api.myproject.com |
Dockerfile:
FROM node:20-alpine AS builder
RUN corepack enable && corepack prepare pnpm@9 --activate
WORKDIR /app
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY apps/api/package.json apps/api/
COPY packages/ packages/
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm --filter @vera-sesiom/api build
FROM node:20-alpine
RUN corepack enable && corepack prepare pnpm@9 --activate
WORKDIR /app
COPY --from=builder /app/apps/api/dist ./dist
COPY --from=builder /app/apps/api/package.json ./
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/main.js"]
Use Dokploy's built-in database service:
| Setting | Value |
|---|---|
| Type | PostgreSQL |
| Version | 16 |
| Volume | /data/postgres/myapp (persistent) |
| Backup | Daily automated via Dokploy |
NEVER expose the database port publicly. Connect via Docker internal network.
For projects that prefer config-as-code:
# docker-compose.yml (deployed via Dokploy Compose feature)