Feature Flags
Open Source
Deploy Unleash Feature Flag Server
Self-hosted LaunchDarkly alternative with first-party SDKs for Node, Python, Go, Ruby, Java, .NET, PHP, Rust, and browser environments.
At a Glance
| Project | Unleash 6.x |
| License | Apache 2.0 |
| Recommended Plan | RamNode Cloud VPS 2 vCPU / 4 GB |
| OS | Ubuntu 24.04 LTS |
| Stack | Node 20 + PostgreSQL 16 |
1
System Prep
Base packages
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg ca-certificates ufw nginx certbot \
python3-certbot-nginx postgresql postgresql-contrib build-essential2
PostgreSQL Database
Create role + DB
sudo -u postgres psql <<EOF
CREATE USER unleash WITH ENCRYPTED PASSWORD '<strong-database-password>';
CREATE DATABASE unleash OWNER unleash;
GRANT ALL PRIVILEGES ON DATABASE unleash TO unleash;
ALTER DATABASE unleash SET timezone TO 'UTC';
EOF
PGPASSWORD='<strong-database-password>' psql -h 127.0.0.1 -U unleash -d unleash -c "SELECT version();"3
Install Node.js 20 LTS
From NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node --version && npm --version4
Install Unleash
Service user + install
sudo useradd --system --shell /bin/bash --home-dir /opt/unleash --create-home unleash
sudo mkdir -p /opt/unleash /var/log/unleash
sudo chown -R unleash:unleash /opt/unleash /var/log/unleash
sudo -u unleash bash <<'EOF'
cd /opt/unleash
npm init -y
npm install unleash-server@latest
EOF/opt/unleash/server.js
const unleash = require('unleash-server');
unleash.start({
db: {
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_NAME,
user: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
ssl: false,
},
server: {
port: process.env.HTTP_PORT || 4242,
host: process.env.HTTP_HOST || '127.0.0.1',
},
authentication: { type: process.env.AUTH_TYPE || 'open-source', createAdminUser: true },
secureHeaders: true,
enableOAS: true,
}).then(i => console.log('Unleash listening on', i.app.get('host'), i.app.get('port')))
.catch(err => { console.error(err); process.exit(1); });5
Environment + systemd
/etc/unleash/unleash.env
DATABASE_HOST=127.0.0.1
DATABASE_PORT=5432
DATABASE_NAME=unleash
DATABASE_USERNAME=unleash
DATABASE_PASSWORD=<strong-database-password>
HTTP_HOST=127.0.0.1
HTTP_PORT=4242
UNLEASH_URL=https://unleash.example.com
AUTH_TYPE=open-source
LOG_LEVEL=info
NODE_ENV=productionLock the env file
sudo mkdir -p /etc/unleash
sudo chmod 0640 /etc/unleash/unleash.env
sudo chown root:unleash /etc/unleash/unleash.env/etc/systemd/system/unleash.service
[Unit]
Description=Unleash Feature Flag Server
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
[Service]
Type=simple
User=unleash
Group=unleash
WorkingDirectory=/opt/unleash
EnvironmentFile=/etc/unleash/unleash.env
ExecStart=/usr/bin/node /opt/unleash/server.js
Restart=on-failure
RestartSec=10
StandardOutput=append:/var/log/unleash/unleash.log
StandardError=append:/var/log/unleash/unleash-error.log
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/unleash /var/log/unleash
[Install]
WantedBy=multi-user.targetEnable
sudo systemctl daemon-reload
sudo systemctl enable --now unleash
sudo tail -f /var/log/unleash/unleash.log
# Capture the auto-generated admin password from the first-start log6
Nginx + TLS + Login Rate Limiting
UFW
sudo ufw default deny incoming && sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
sudo ufw enableIn /etc/nginx/nginx.conf http {}
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=10r/m;/etc/nginx/sites-available/unleash
upstream unleash_backend { server 127.0.0.1:4242; keepalive 32; }
server {
listen 80;
server_name unleash.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name unleash.example.com;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
proxy_read_timeout 90s;
client_max_body_size 50m;
location / {
proxy_pass http://unleash_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /auth/simple/login {
limit_req zone=login_limit burst=5 nodelay;
proxy_pass http://unleash_backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}Enable + cert
sudo ln -s /etc/nginx/sites-available/unleash /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d unleash.example.com --redirect --agree-tos -m admin@example.com7
Backups
/usr/local/bin/backup-unleash.sh
#!/bin/bash
set -euo pipefail
TS=$(date +%Y%m%d-%H%M%S)
DEST="/var/backups/unleash"
RETENTION_DAYS=14
mkdir -p "${DEST}"
PGPASSWORD='<strong-database-password>' pg_dump -h 127.0.0.1 -U unleash \
-F custom -f "${DEST}/unleash-${TS}.dump" unleash
tar -czf "${DEST}/unleash-config-${TS}.tar.gz" /etc/unleash /etc/nginx/sites-available/unleash
find "${DEST}" -name 'unleash-*.dump' -mtime +${RETENTION_DAYS} -delete
find "${DEST}" -name 'unleash-config-*.tar.gz' -mtime +${RETENTION_DAYS} -deleteSchedule
sudo chmod 0750 /usr/local/bin/backup-unleash.sh
echo '0 2 * * * root /usr/local/bin/backup-unleash.sh' | sudo tee /etc/cron.d/unleash-backup8
Monitoring (Prometheus)
Add to env file
echo "PROMETHEUS_API=true" | sudo tee -a /etc/unleash/unleash.env
sudo systemctl restart unleashScrape
scrape_configs:
- job_name: unleash
metrics_path: /internal-backstage/prometheus
static_configs:
- targets: ['127.0.0.1:4242']