DigitalOcean
intermediate
35-45 minutes
Droplet Deployment
Deploy applications on DigitalOcean Droplets - virtual machines with full control and flexibility.
What you'll accomplish
Your application running on a Droplet with proper configuration
Prerequisites
- DigitalOcean account
- doctl CLI installed
- SSH key added to account
What are Droplets?
Droplets are DigitalOcean's virtual machines:
- Full control - Root access, any software
- SSD storage - Fast performance
- Simple pricing - Fixed monthly cost
- Quick deployment - Ready in 55 seconds
When to Use Droplets
| Use Case | Why Droplets |
|---|---|
| Custom software | Install anything |
| Legacy apps | Full OS control |
| Databases | Self-managed options |
| Development | SSH access, testing |
| Background jobs | Long-running processes |
Step 1: Create a Droplet
Via CLI
bash# Basic Droplet doctl compute droplet create myserver \ --image ubuntu-22-04-x64 \ --size s-1vcpu-1gb \ --region nyc1 \ --ssh-keys $(doctl compute ssh-key list --format ID --no-header | head -1) # With multiple options doctl compute droplet create myserver \ --image ubuntu-22-04-x64 \ --size s-2vcpu-2gb \ --region nyc1 \ --ssh-keys KEY_ID \ --enable-monitoring \ --enable-backups \ --vpc-uuid VPC_ID \ --tag-names "production,web"
Via Control Panel
- Go to Create → Droplets
- Choose region
- Select image (Ubuntu 22.04 recommended)
- Choose size
- Add SSH key
- Click Create Droplet
Droplet Sizes
| Size | vCPU | RAM | Storage | Bandwidth | Price |
|---|---|---|---|---|---|
| s-1vcpu-512mb-10gb | 1 | 512 MB | 10 GB | 500 GB | $4/mo |
| s-1vcpu-1gb | 1 | 1 GB | 25 GB | 1 TB | $6/mo |
| s-1vcpu-2gb | 1 | 2 GB | 50 GB | 2 TB | $12/mo |
| s-2vcpu-2gb | 2 | 2 GB | 60 GB | 3 TB | $18/mo |
| s-2vcpu-4gb | 2 | 4 GB | 80 GB | 4 TB | $24/mo |
| s-4vcpu-8gb | 4 | 8 GB | 160 GB | 5 TB | $48/mo |
Available Images
bash# List public images doctl compute image list --public # Common images: # ubuntu-24-04-x64 - Ubuntu 24.04 LTS # ubuntu-22-04-x64 - Ubuntu 22.04 LTS # debian-12-x64 - Debian 12 # centos-stream-9-x64 - CentOS Stream 9 # docker-20-04 - Docker on Ubuntu 20.04 # nodejs - Node.js pre-installed
Step 2: Connect via SSH
Get Droplet IP
bash# List Droplets doctl compute droplet list # Get specific Droplet IP doctl compute droplet get DROPLET_ID --format PublicIPv4 --no-header
SSH Connection
bash# Connect via doctl doctl compute ssh myserver # Or standard SSH ssh root@YOUR_DROPLET_IP
First Login
bash# Update system apt update && apt upgrade -y # Create non-root user adduser deploy usermod -aG sudo deploy # Set up SSH for new user mkdir -p /home/deploy/.ssh cp ~/.ssh/authorized_keys /home/deploy/.ssh/ chown -R deploy:deploy /home/deploy/.ssh # Disable root login (optional but recommended) sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config systemctl restart sshd
Step 3: Configure Firewall
Using UFW
bash# Enable firewall ufw default deny incoming ufw default allow outgoing # Allow SSH ufw allow 22/tcp # Allow HTTP/HTTPS ufw allow 80/tcp ufw allow 443/tcp # Enable firewall ufw enable # Check status ufw status
Using DigitalOcean Cloud Firewall
bash# Create firewall doctl compute firewall create \ --name myapp-firewall \ --inbound-rules "protocol:tcp,ports:22,address:0.0.0.0/0 protocol:tcp,ports:80,address:0.0.0.0/0 protocol:tcp,ports:443,address:0.0.0.0/0" \ --outbound-rules "protocol:tcp,ports:all,address:0.0.0.0/0 protocol:udp,ports:all,address:0.0.0.0/0" \ --droplet-ids DROPLET_ID
Step 4: Deploy Your Application
Node.js Application
bash# Install Node.js curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt install -y nodejs # Clone your app cd /var/www git clone https://github.com/username/myapp.git cd myapp # Install dependencies npm ci --production # Build (if needed) npm run build
Create Systemd Service
bashcat > /etc/systemd/system/myapp.service << 'EOF' [Unit] Description=My Node.js Application After=network.target [Service] Type=simple User=deploy WorkingDirectory=/var/www/myapp ExecStart=/usr/bin/node server.js Restart=on-failure RestartSec=10 Environment=NODE_ENV=production Environment=PORT=3000 [Install] WantedBy=multi-user.target EOF # Enable and start systemctl daemon-reload systemctl enable myapp systemctl start myapp # Check status systemctl status myapp
Configure Nginx
bash# Install Nginx apt install -y nginx # Configure reverse proxy cat > /etc/nginx/sites-available/myapp << 'EOF' server { listen 80; server_name example.com www.example.com; location / { proxy_pass http://localhost: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_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; } } EOF # Enable site ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default # Test and restart nginx -t systemctl restart nginx
Step 5: SSL with Let's Encrypt
bash# Install Certbot apt install -y certbot python3-certbot-nginx # Get certificate certbot --nginx -d example.com -d www.example.com # Auto-renewal (already configured) certbot renew --dry-run
Step 6: Docker Deployment
Install Docker
bash# Install Docker curl -fsSL https://get.docker.com | sh # Add user to docker group usermod -aG docker deploy
Run Container
bash# Pull and run docker pull ghcr.io/username/myapp:latest docker run -d \ --name myapp \ -p 80:3000 \ --restart unless-stopped \ -e NODE_ENV=production \ ghcr.io/username/myapp:latest
Docker Compose
yaml# docker-compose.yml version: '3.8' services: web: image: ghcr.io/username/myapp:latest ports: - "3000:3000" environment: - NODE_ENV=production - DATABASE_URL=${DATABASE_URL} restart: unless-stopped nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - /etc/letsencrypt:/etc/letsencrypt:ro depends_on: - web restart: unless-stopped
Step 7: User Data (Automation)
Automate setup with cloud-init:
bashdoctl compute droplet create myserver \ --image ubuntu-22-04-x64 \ --size s-1vcpu-1gb \ --region nyc1 \ --ssh-keys KEY_ID \ --user-data-file ./setup.sh
Example setup.sh
bash#!/bin/bash # Update system apt-get update apt-get upgrade -y # Install Node.js curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs nginx # Install app cd /var/www git clone https://github.com/username/myapp.git cd myapp npm ci --production # Create systemd service cat > /etc/systemd/system/myapp.service << 'SVCEOF' [Unit] Description=My Application After=network.target [Service] Type=simple User=root WorkingDirectory=/var/www/myapp ExecStart=/usr/bin/node server.js Restart=on-failure Environment=NODE_ENV=production Environment=PORT=3000 [Install] WantedBy=multi-user.target SVCEOF systemctl enable myapp systemctl start myapp # Configure nginx cat > /etc/nginx/sites-available/myapp << 'NGXEOF' server { listen 80; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Host $host; } } NGXEOF ln -sf /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default systemctl restart nginx
Step 8: Monitoring
Enable Monitoring Agent
bash# During creation doctl compute droplet create myserver \ --enable-monitoring # Or install manually curl -sSL https://repos.insights.digitalocean.com/install.sh | bash
View Metrics
- Control Panel → Droplet → Graphs
- CPU, Memory, Disk, Bandwidth
Set Up Alerts
- Control Panel → Monitoring → Create Alert
- Select metric (CPU, Memory, Disk)
- Set threshold
- Add notification channel
Step 9: Backups and Snapshots
Enable Backups
bash# On creation doctl compute droplet create myserver \ --enable-backups # Or enable for existing # (via Control Panel: Droplet → Backups → Enable)
Backups:
- Weekly automatic
- 4-week retention
- 20% of Droplet cost
Create Snapshot
bash# Create snapshot doctl compute droplet-action snapshot DROPLET_ID \ --snapshot-name "myserver-$(date +%Y%m%d)" # List snapshots doctl compute snapshot list --resource droplet
Step 10: Scaling
Resize Droplet
bash# Power off first doctl compute droplet-action power-off DROPLET_ID # Resize doctl compute droplet-action resize DROPLET_ID --size s-2vcpu-4gb # Power on doctl compute droplet-action power-on DROPLET_ID
Horizontal Scaling
Create multiple Droplets with a Load Balancer:
bash# Create Droplets for i in 1 2 3; do doctl compute droplet create web-$i \ --image ubuntu-22-04-x64 \ --size s-1vcpu-1gb \ --region nyc1 \ --ssh-keys KEY_ID \ --tag-names "web" done # Create Load Balancer doctl compute load-balancer create \ --name mylb \ --region nyc1 \ --tag-name web \ --forwarding-rules "entry_protocol:http,entry_port:80,target_protocol:http,target_port:3000"
Troubleshooting
Can't SSH
bash# Check Droplet is running doctl compute droplet get DROPLET_ID # Try with verbose ssh -v root@IP # Check firewall doctl compute firewall list
Service Won't Start
bash# Check logs journalctl -u myapp.service -n 50 # Check service status systemctl status myapp # Try manual start node /var/www/myapp/server.js
Out of Memory
bash# Check memory free -h # Add swap fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab
Note
Checkpoint: Create a Droplet, deploy your application, configure Nginx, and verify it's accessible via the public IP.