Spaces:
Running
VPS Deployment Guide
Deploy OSW Studio on a VPS with full security hardening. Tested on Hetzner Cloud, but applies to any Ubuntu/Debian VPS.
Pre-Creation (Hetzner Console)
Skip this section if using a different VPS provider. The server setup steps below work on any Ubuntu 22.04+ server.
1. Add SSH Key
Security β SSH Keys β Add SSH Key
If you don't have one locally, generate it first:
ssh-keygen -t ed25519 -C "osws-server"
cat ~/.ssh/id_ed25519.pub
Paste the public key into Hetzner.
2. Create Cloud Firewall
Firewalls β Create Firewall
Inbound rules (TCP only):
| Port | Protocol | Source |
|---|---|---|
| 22 | TCP | Any |
| 80 | TCP | Any |
| 443 | TCP | Any |
Do NOT add port 3000 or any other app ports.
3. Create Server
- Select your SSH key
- Attach the firewall
- Smallest instance (CX11/CX21) is fine for testing
Server Setup
SSH into the server:
ssh root@<your-ip>
Update System
apt update && apt upgrade -y
Create Non-Root User
adduser osws --disabled-password --gecos ""
mkdir -p /home/osws/.ssh
cp ~/.ssh/authorized_keys /home/osws/.ssh/
chown -R osws:osws /home/osws/.ssh
chmod 700 /home/osws/.ssh
chmod 600 /home/osws/.ssh/authorized_keys
Harden SSH
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/PermitRootLogin yes/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
systemctl restart ssh
Install fail2ban
apt install fail2ban -y
systemctl enable fail2ban --now
Add Swap (Prevents OOM on Small Instances)
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
Install & Configure Nginx
apt install nginx -y
cat > /etc/nginx/sites-available/osws << 'EOF'
server {
listen 80 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
}
}
EOF
ln -s /etc/nginx/sites-available/osws /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
App Deployment
Switch to osws User
su - osws
Install Node.js
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install 20
Clone Repository
git clone https://github.com/o-stahl/osw-studio.git
cd osw-studio
Create Environment File
SESSION_SECRET=$(openssl rand -base64 32)
ANALYTICS_SECRET=$(openssl rand -base64 32)
SECRETS_ENCRYPTION_KEY=$(openssl rand -base64 32)
cat > .env << EOF
NEXT_PUBLIC_SERVER_MODE=true
SESSION_SECRET=$SESSION_SECRET
SECURE_COOKIES=false
ANALYTICS_SECRET=$ANALYTICS_SECRET
SECRETS_ENCRYPTION_KEY=$SECRETS_ENCRYPTION_KEY
EOF
Note:
SECURE_COOKIES=falseis required when running HTTP without SSL. Remove this line after adding HTTPS.No
ADMIN_PASSWORDneeded. On first visit to/admin, you'll create the admin account interactively.
Build & Start
npm install
npm run build
npm install -g pm2
pm2 start npm --name "osws" -- start
pm2 save
Enable PM2 on Boot
Exit back to root (exit) and run:
env PATH=$PATH:/home/osws/.nvm/versions/node/v20.18.1/bin pm2 startup systemd -u osws --hp /home/osws
Note: Adjust the Node version path if you installed a different version.
Access
- Studio:
http://<your-ip>/ - Admin:
http://<your-ip>/admin
Updating OSW Studio
su - osws
cd ~/osw-studio
git pull
npm install
npm run build
pm2 restart osws
Important: Any changes to
NEXT_PUBLIC_*environment variables require a rebuild (npm run build) β these are baked in at compile time.
Adding HTTPS (Recommended)
Once you have a domain pointing to your server:
As root:
apt install certbot python3-certbot-nginx -y
certbot --nginx -d your-domain.com
Then update the environment and rebuild:
su - osws
cd ~/osw-studio
# Edit .env to remove SECURE_COOKIES=false
nano .env
npm run build
pm2 restart osws
Security Checklist
- β Never expose port 3000 directly β always use nginx as reverse proxy
- β
App runs as non-root user
osws - β SSH is key-only, no password authentication
- β Cloud firewall blocks all ports except 22, 80, 443
- β fail2ban protects against brute force attempts
- β Swap prevents out-of-memory crashes on small instances
Next Steps
- Server Mode - Full Server Mode documentation
- Deployment Publishing - Publish deployments with analytics and SEO
- Backend - Database, edge functions, secrets