Self-Hosting
MarkDocs runs on your own infrastructure. Docker Compose for quick setups, or deploy to Railway/Render/any Node.js host.
Docker Compose
The simplest way to deploy:
git clone https://github.com/thakurkharel/markdocs.git
cd markdocsCreate a .env file:
POSTGRES_PASSWORD=a-strong-random-password
JWT_SECRET=another-strong-random-secret
PORT=3001Start the services:
docker compose up -dRailway
One-click deploy with a Postgres addon:
- Create a new project on Railway
- Add a PostgreSQL service
- Add a new service from your GitHub repo (fork or import
thakurkharel/markdocs) - Set environment variables:
DATABASE_URL → (auto-linked from the Postgres service)
DIRECT_URL → (same as DATABASE_URL)
JWT_SECRET → a-strong-random-secret
PORT → 3001- Railway auto-detects the build. The included
railway.tomlruns migrations on deploy.
The repo includes a railway.toml that handles the start command:
[build]
builder = "nixpacks"
[deploy]
startCommand = "npx prisma migrate deploy && npx tsx server.ts"
healthcheckPath = "/"
restartPolicyType = "on_failure"Render
Similar to Railway:
- Create a new Web Service on Render
- Connect your repo
- Set build command:
npm install && npx prisma generate && npm run build - Set start command:
npx prisma migrate deploy && npx tsx server.ts - Add a PostgreSQL database and link
DATABASE_URL - Add
JWT_SECRETandPORT=3001as environment variables
Fly.io
fly launch
fly postgres create --name markdocs-db
fly postgres attach markdocs-db
fly secrets set JWT_SECRET=a-strong-random-secret
fly deployAdd to your fly.toml:
[processes]
app = "npx prisma migrate deploy && npx tsx server.ts"Reverse Proxy
If running on a VPS, put MarkDocs behind a reverse proxy for HTTPS.
Caddy (automatic HTTPS):
markdocs.yourdomain.com {
reverse_proxy localhost:3001
}nginx:
server {
listen 443 ssl;
server_name markdocs.yourdomain.com;
location / {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}The Upgrade and Connection headers are required for WebSocket support (real-time collaboration).
Database Backups
The PostgreSQL data is stored in a Docker volume (pgdata). Back it up regularly:
# Dump the database
docker exec markdocs-db-1 pg_dump -U markdocs markdocs > backup.sql
# Restore from backup
cat backup.sql | docker exec -i markdocs-db-1 psql -U markdocs markdocsFor Railway/Render, use the platform’s built-in backup features.
Updating
git pull
docker compose build
docker compose up -dFor Railway/Render, push to your repo and the platform auto-deploys. Migrations run automatically on startup.
Environment Variables
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string |
DIRECT_URL | Yes | Same as DATABASE_URL (for Prisma) |
JWT_SECRET | Yes | Secret for signing auth tokens |
PORT | No | Server port (default: 3001) |
POSTGRES_PASSWORD | Docker only | Password for the Docker Postgres instance |
Resource Requirements
MarkDocs is lightweight:
- CPU: 1 core minimum
- RAM: 512MB minimum (1GB recommended)
- Disk: Depends on document volume, typically under 1GB