DigitalOcean Deployment
Complete step-by-step guide to deploy your WebSocket IoT server to DigitalOcean with auto-deploy on git push.
Full port control — Use any port you want, no TLS forced on your custom domain
Plain ws:// — No-TLS devices connect directly (e.g., TM20 terminals)
Cost — $6–12/month for a basic droplet, auto-deploy included
5500, 7788, 8080, 9000. You'll need to open it in the firewall.Selected port: 5500 — this will be used throughout the commands below.
- A.
Go to digitalocean.com and sign up (free $200 credit)
- B.
Click Create → Droplets
- C.
Choose these settings:
- • Image: Ubuntu 22.04 (or latest LTS)
- • Plan: Basic ($6/month)
- • Region: Choose one close to your devices
- • Authentication: SSH key (recommended) or password
- D.
Click Create Droplet and wait 2–3 minutes
Copy your droplet's IP address — you'll need it throughout this guide.
Open your terminal and connect:
ssh root@YOUR_DROPLET_IPOnce connected, update the system:
sudo apt update && sudo apt upgrade -yInstall Node.js 20:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejsInstall pnpm (required for this project):
sudo npm install -g pnpmVerify installation:
node --version && pnpm --versionClone your v0-websocket-iot-protocol repo:
git clone https://github.com/cyberalphatech/v0-websocket-iot-protocol.git
cd v0-websocket-iot-protocolCreate a .env.local file with your Supabase credentials:
nano .env.localPaste this and fill in your actual values:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key_here
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key_here
PORT=5500Save with Ctrl+O, press Enter, then Ctrl+X to exit nano.
Find these values in your Supabase project settings (Settings → API).
Install dependencies:
pnpm install --frozen-lockfileBuild the project:
pnpm buildYour droplet has Ubuntu's firewall (ufw). Open the WebSocket port:
sudo ufw allow 22/tcp
sudo ufw allow 5500/tcp
sudo ufw enableVerify the ports are open:
sudo ufw statusCritical: Always open port 22 (SSH) first, or you'll lock yourself out!
Install PM2 (keeps your server running 24/7):
sudo npm install -g pm2Start the server with PM2:
pm2 start "npm start" --name iot-hubSave PM2 to auto-restart on reboot:
pm2 startup
pm2 saveCheck that the server is running:
pm2 statusYour server is now live at ws://YOUR_DROPLET_IP:5500
On your TM20 or device, set the Server menu to:
YesYesYOUR_DROPLET_IP5500Device will connect as ws://YOUR_DROPLET_IP:5500 — no TLS, plain WebSocket.
Every time you push to main, the droplet will auto-update. Here's how:
Step A: Generate SSH key on droplet
ssh-keygen -t ed25519 -f ~/.ssh/github_deploy -N ""
cat ~/.ssh/github_deploy.pub >> ~/.ssh/authorized_keysStep B: Get the private key
cat ~/.ssh/github_deployCopy the entire output (starts with -----BEGIN PRIVATE KEY-----)
Step C: Add secrets to GitHub
- 1. Go to your GitHub repo → Settings → Secrets and variables → Actions
- 2. Click New repository secret
- 3. Create two secrets:
- • Name:
DEPLOY_KEY, paste the private key - • Name:
DROPLET_IP, paste your droplet IP
- • Name:
Step D: Create GitHub Actions workflow
Create file .github/workflows/deploy.yml in your repo with:
name: Auto-Deploy to DigitalOcean
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DROPLET_IP }}
username: root
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd ~/v0-websocket-iot-protocol
git pull origin main
pnpm install --frozen-lockfile
pnpm build
pm2 restart iot-hub
pm2 saveDone! Now every git push triggers auto-deploy. Watch your droplet update in seconds.
Check server status:
pm2 statusView live logs:
pm2 logs iot-hubTest WebSocket port from local:
nc -zv YOUR_DROPLET_IP 5500Check GitHub Actions workflow (after you push):
Go to your GitHub repo → Actions tab to see deployment status
You're Live!
Your WebSocket server is now live on DigitalOcean with auto-deploy. Your IoT devices can connect to ws://YOUR_DROPLET_IP:5500 with plain WebSocket — no TLS required.