Skip to main content

Self-Hosting Guide

Deploy LinkForty on your own infrastructure with complete control over your data.

Why Self-Host?

Control & Flexibility:

  • ✅ No per-install fees (unlimited scaling)
  • ✅ No vendor lock-in
  • ✅ Deploy anywhere (AWS, GCP, Azure, on-premise)

Data Privacy:

  • ✅ Complete data ownership
  • ✅ GDPR/CCPA compliance on your terms
  • ✅ No third-party data sharing

Customization:

  • ✅ Full source code access (MIT license)
  • ✅ Custom features and integrations
  • ✅ White-label deployment

System Requirements

Minimum Specifications

Server:

  • CPU: 2 cores
  • RAM: 4 GB
  • Storage: 20 GB SSD
  • OS: Ubuntu 20.04+ / Debian 11+ / RHEL 8+

Software:

  • Docker 20.10+ and Docker Compose 2.0+
  • OR Node.js 18+ with PostgreSQL 14+ and Redis 7+

Expected Load Capacity:

  • ~1,000 requests/minute
  • ~100,000 links
  • ~1M clicks/month

Server:

  • CPU: 4 cores
  • RAM: 8 GB
  • Storage: 100 GB SSD
  • OS: Ubuntu 22.04 LTS

Expected Load Capacity:

  • ~10,000 requests/minute
  • ~1M links
  • ~10M clicks/month

Cloud Provider Options

Recommended instance types for minimum specifications:

ProviderInstance TypeSpecs
DigitalOceanDroplet (Basic)2 CPU, 4GB RAM
AWSt3.medium2 CPU, 4GB RAM
Google Cloude2-medium2 CPU, 4GB RAM
HetznerCX212 CPU, 4GB RAM
VultrRegular Performance2 CPU, 4GB RAM

Installation Methods

Choose your deployment method:

Fastest and easiest deployment. Everything configured out of the box.

Method 2: Manual Installation

For custom setups or when Docker isn't available.

Method 3: Kubernetes

For enterprise deployments with high availability.


Step 1: Clone Repository

git clone https://github.com/linkforty/linkforty-cloud.git
cd linkforty-cloud

Step 2: Configure Environment

Create .env file:

cp .env.example .env
nano .env

Required environment variables:

# Database
DATABASE_URL=postgresql://linkforty:your-strong-password@postgres:5432/linkforty
POSTGRES_USER=linkforty
POSTGRES_PASSWORD=your-strong-password
POSTGRES_DB=linkforty

# Redis
REDIS_URL=redis://redis:6379

# Application
NODE_ENV=production
PORT=3000
FRONTEND_URL=https://yourdomain.com

# Security (CHANGE THESE!)
JWT_SECRET=your-super-secret-jwt-key-at-least-32-characters-long
ENCRYPTION_KEY=your-encryption-key-32-characters-minimum

# Optional: Email (for user invitations)
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASSWORD=your-sendgrid-api-key
SMTP_FROM=noreply@yourdomain.com

# Optional: S3 (for QR code storage)
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_REGION=us-east-1
AWS_S3_BUCKET=linkforty-qrcodes

Security Note: Generate strong secrets with:

# Generate JWT secret
openssl rand -base64 48

# Generate encryption key
openssl rand -base64 32

Step 3: Build and Start Services

# Build Docker images
docker-compose build

# Start all services
docker-compose up -d

This starts:

  • Frontend: React app (Nginx)
  • Backend: Fastify API server
  • PostgreSQL: Database
  • Redis: Cache and session storage

Step 4: Run Database Migrations

docker-compose exec backend npm run migrate

Step 5: Create Admin User

docker-compose exec backend npm run create-admin

# You'll be prompted for:
# - Email: admin@yourdomain.com
# - Password: (your secure password)
# - Organization Name: Your Company

Step 6: Verify Installation

# Check all services are running
docker-compose ps

# Should show:
# linkforty-frontend Up 80, 443
# linkforty-backend Up 3000
# linkforty-postgres Up 5432
# linkforty-redis Up 6379

Visit http://your-server-ip and log in with your admin credentials.

Step 7: Set Up SSL (Required for Production)

Option A: Using Let's Encrypt (Free)

Install Certbot:

sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

Generate certificate:

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Update docker-compose.yml to use SSL:

services:
frontend:
ports:
- "80:80"
- "443:443"
volumes:
- /etc/letsencrypt:/etc/letsencrypt:ro

Option B: Using Cloudflare (Free SSL + CDN)

  1. Point your domain to Cloudflare nameservers
  2. Enable Full (strict) SSL mode in Cloudflare dashboard
  3. Create origin certificate in Cloudflare
  4. Install origin certificate on your server
  5. Enable Always Use HTTPS in Cloudflare

Step 8: Configure Nginx (Optional)

For better performance, configure Nginx reverse proxy:

# /etc/nginx/sites-available/linkforty
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

# Frontend
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_cache_bypass $http_upgrade;
}

# Backend API
location /api {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
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;
}

# Short link redirects
location ~ ^/[a-zA-Z0-9]+$ {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

Enable site:

sudo ln -s /etc/nginx/sites-available/linkforty /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Method 2: Manual Installation

Step 1: Install Dependencies

# Update system
sudo apt-get update && sudo apt-get upgrade -y

# Install Node.js 18
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs

# Install PostgreSQL 14
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install -y postgresql-14

# Install Redis 7
sudo apt-get install -y redis-server

Step 2: Configure PostgreSQL

# Create database and user
sudo -u postgres psql << EOF
CREATE DATABASE linkforty;
CREATE USER linkforty WITH PASSWORD 'your-strong-password';
GRANT ALL PRIVILEGES ON DATABASE linkforty TO linkforty;
\q
EOF

Step 3: Clone and Build

# Clone repository
git clone https://github.com/linkforty/linkforty-cloud.git
cd linkforty-cloud

# Install dependencies
npm install
cd backend && npm install && cd ..

# Build frontend
npm run build

# Build backend
cd backend && npm run build && cd ..

Step 4: Configure Environment

cp .env.example .env
nano .env

Set production values (same as Docker Compose method).

Step 5: Run Migrations

cd backend
npm run migrate
cd ..

Step 6: Set Up systemd Services

Create backend service:

sudo nano /etc/systemd/system/linkforty-backend.service
[Unit]
Description=LinkForty Backend
After=network.target postgresql.service redis.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/linkforty-cloud/backend
Environment="NODE_ENV=production"
EnvironmentFile=/opt/linkforty-cloud/.env
ExecStart=/usr/bin/node dist/index.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

Create frontend service:

sudo nano /etc/systemd/system/linkforty-frontend.service
[Unit]
Description=LinkForty Frontend
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/linkforty-cloud
ExecStart=/usr/bin/npx serve -s dist -l 3001
Restart=on-failure

[Install]
WantedBy=multi-user.target

Enable and start services:

sudo systemctl daemon-reload
sudo systemctl enable linkforty-backend linkforty-frontend
sudo systemctl start linkforty-backend linkforty-frontend

# Check status
sudo systemctl status linkforty-backend
sudo systemctl status linkforty-frontend

Method 3: Kubernetes

Prerequisites

  • Kubernetes cluster (EKS, GKE, AKS, or self-hosted)
  • kubectl configured
  • Helm 3+

Step 1: Add Helm Repository

helm repo add linkforty https://charts.linkforty.com
helm repo update

Step 2: Create Values File

# values.yaml
replicaCount: 3

image:
repository: linkforty/linkforty-cloud
tag: "latest"
pullPolicy: IfNotPresent

service:
type: LoadBalancer
port: 80

ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: linkforty.yourdomain.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: linkforty-tls
hosts:
- linkforty.yourdomain.com

postgresql:
enabled: true
auth:
username: linkforty
password: your-strong-password
database: linkforty
primary:
persistence:
size: 20Gi

redis:
enabled: true
auth:
enabled: false
master:
persistence:
size: 8Gi

env:
JWT_SECRET: your-super-secret-jwt-key
ENCRYPTION_KEY: your-encryption-key

resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi

autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80

Step 3: Install with Helm

helm install linkforty linkforty/linkforty-cloud -f values.yaml

Step 4: Verify Deployment

kubectl get pods
kubectl get services
kubectl logs -l app=linkforty

Post-Installation Setup

1. Configure Custom Domain

Update DNS records:

A    linkforty.yourdomain.com     → your-server-ip
A *.linkforty.yourdomain.com → your-server-ip (for custom domains)

2. Set Up Backups

PostgreSQL Backup Script

#!/bin/bash
# /opt/linkforty-cloud/backup.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/linkforty"
mkdir -p $BACKUP_DIR

# Backup database
docker-compose exec -T postgres pg_dump -U linkforty linkforty | gzip > "$BACKUP_DIR/linkforty_$DATE.sql.gz"

# Keep only last 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete

# Upload to S3 (optional)
aws s3 cp "$BACKUP_DIR/linkforty_$DATE.sql.gz" s3://your-backup-bucket/

Add to crontab:

crontab -e

# Daily backup at 2 AM
0 2 * * * /opt/linkforty-cloud/backup.sh

3. Set Up Monitoring

Using Docker Stats

docker stats linkforty-backend linkforty-frontend

Using Prometheus + Grafana

# docker-compose.yml additions
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"

grafana:
image: grafana/grafana
ports:
- "3002:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin

4. Configure Firewall

# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Allow SSH (change port if needed)
sudo ufw allow 22/tcp

# Enable firewall
sudo ufw enable

5. Set Up Log Rotation

sudo nano /etc/logrotate.d/linkforty
/opt/linkforty-cloud/logs/*.log {
daily
rotate 14
compress
delaycompress
notifempty
missingok
sharedscripts
postrotate
docker-compose restart backend frontend
endscript
}

Updating LinkForty

Docker Compose

cd /opt/linkforty-cloud

# Pull latest code
git pull origin main

# Rebuild images
docker-compose build

# Run migrations (if needed)
docker-compose exec backend npm run migrate

# Restart services
docker-compose up -d

Manual Installation

cd /opt/linkforty-cloud

# Pull latest code
git pull origin main

# Update dependencies
npm install
cd backend && npm install && cd ..

# Rebuild
npm run build
cd backend && npm run build && cd ..

# Run migrations
cd backend && npm run migrate && cd ..

# Restart services
sudo systemctl restart linkforty-backend linkforty-frontend

Troubleshooting

Backend Won't Start

# Check logs
docker-compose logs backend

# Common issues:
# 1. Database not ready - wait 10 seconds and retry
# 2. Redis not accessible - check REDIS_URL
# 3. Port 3000 in use - change PORT in .env

Frontend Shows "API Connection Error"

# Check VITE_API_URL in .env
# Should be: https://yourdomain.com/api

# Verify backend is running
curl http://localhost:3000/api/health

Database Connection Errors

# Test PostgreSQL connection
docker-compose exec postgres psql -U linkforty -d linkforty -c "SELECT 1;"

# Check DATABASE_URL format:
# postgresql://username:password@host:port/database

High Memory Usage

# Increase PostgreSQL shared_buffers
docker-compose exec postgres psql -U linkforty -d linkforty -c "ALTER SYSTEM SET shared_buffers = '256MB';"
docker-compose restart postgres

# Increase Node.js memory limit
# In docker-compose.yml:
environment:
- NODE_OPTIONS=--max-old-space-size=2048

Production Checklist

Before going live:

  • ✅ SSL certificate installed and working
  • ✅ Strong JWT_SECRET and ENCRYPTION_KEY generated
  • ✅ Database backups configured (daily minimum)
  • ✅ Firewall rules configured
  • ✅ Monitoring set up (Prometheus/Grafana or cloud provider)
  • ✅ Log rotation configured
  • ✅ DNS records pointing to server
  • ✅ SMTP configured for user invitations
  • ✅ Rate limiting enabled (default: 100 req/min per IP)
  • ✅ Admin user created
  • ✅ Test link created and working
  • ✅ Health check endpoint responding (/api/health)

Getting Help

Platform Guides - Usage documentation

Next Steps