Skip to content

Instantly share code, notes, and snippets.

@Chizaruu
Last active October 23, 2025 10:28
Show Gist options
  • Select an option

  • Save Chizaruu/de706bd54790b2d7d4b6d7920827d8a4 to your computer and use it in GitHub Desktop.

Select an option

Save Chizaruu/de706bd54790b2d7d4b6d7920827d8a4 to your computer and use it in GitHub Desktop.
Complete SFTPGo setup guide for Ubuntu - Self-hosted SFTP server with web UI. Costs $12/month vs $220/month for Azure. Includes installation, user management, security, HTTPS setup, and troubleshooting.

SFTPGo Setup Guide - Complete SFTP Server with Web UI

TL;DR: Install SFTPGo on Ubuntu, get a web-based SFTP management interface with mandatory HTTPS. Costs $12/month vs $220/month for Azure Blob SFTP.

Quick Start

# Add repo and install
sudo add-apt-repository ppa:sftpgo/sftpgo
sudo apt update && sudo apt install sftpgo -y

# Configure firewall
sudo ufw allow 22/tcp    # SSH
sudo ufw allow 80/tcp    # HTTP (for SSL setup/redirect)
sudo ufw allow 443/tcp   # HTTPS
sudo ufw allow 2022/tcp  # SFTP
sudo ufw enable

# Set up HTTPS (see HTTPS Setup section - DO THIS BEFORE accessing web UI)
# Then access web UI and create admin account
# https://your_domain.com OR https://your_server_ip (with tunnel)

⚠️ CRITICAL: Never use HTTP for the web admin interface. See HTTPS Setup section below.


Full Setup

1. Server Setup

Requirements:

  • Ubuntu 24.04 or 22.04 LTS
  • 2GB RAM minimum
  • Root or sudo access

Create DigitalOcean Droplet:

  • OS: Ubuntu 24.04 LTS
  • Plan: Basic $12/month (2GB RAM)
  • Choose datacenter region
  • Authentication: SSH key recommended

Connect:

ssh root@your_server_ip

2. Install SFTPGo

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

# Add SFTPGo repository
sudo add-apt-repository ppa:sftpgo/sftpgo

# Install
sudo apt update
sudo apt install sftpgo -y

# Verify it's running
sudo systemctl status sftpgo

SFTPGo automatically:

  • ✅ Starts on installation
  • ✅ Enables on boot
  • ✅ Creates data directories at /srv/sftpgo/data/

3. Configure Firewall

# Allow required ports
sudo ufw allow 22/tcp     # SSH access
sudo ufw allow 80/tcp     # HTTP (for SSL/redirects)
sudo ufw allow 443/tcp    # HTTPS
sudo ufw allow 2022/tcp   # SFTP connections

# Enable firewall
sudo ufw enable

# Check status
sudo ufw status

# Note: Port 8080 should NOT be publicly accessible

HTTPS Setup (DO THIS BEFORE CREATING ADMIN ACCOUNT)

⚠️ CRITICAL SECURITY REQUIREMENT: The web admin interface must NEVER be accessed over plain HTTP. Choose one of the three secure options below:

Option 1: With Domain Name (Best - Free SSL with Let's Encrypt)

Prerequisites:

  • Own a domain (e.g., yourdomain.com)
  • Point DNS A record to your droplet IP: sftp.yourdomain.com → your_server_ip

Setup:

1. Install Nginx and Certbot:

sudo apt install nginx certbot python3-certbot-nginx -y

2. Create Nginx config:

sudo nano /etc/nginx/sites-available/sftpgo

Paste this simple HTTP-only configuration (certbot will add SSL automatically):

server {
    listen 80;
    server_name sftp.yourdomain.com;

    location / {
        proxy_pass http://localhost:8080;
        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;
        
        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

3. Enable site:

sudo ln -s /etc/nginx/sites-available/sftpgo /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default  # Remove default site
sudo nginx -t
sudo systemctl restart nginx

4. Get FREE SSL certificate:

Certbot will automatically:

  • Get the SSL certificate
  • Add HTTPS configuration to your Nginx config
  • Set up HTTP to HTTPS redirect
  • Add security headers
  • Configure auto-renewal
sudo certbot --nginx -d sftp.yourdomain.com

# Follow prompts:
# Enter email: your-email@domain.com
# Agree to terms: Y
# Share email: N (optional)

After certbot completes, it will have automatically modified your Nginx configuration to include SSL.

5. Verify the setup:

# Check the SSL configuration certbot added
sudo cat /etc/nginx/sites-available/sftpgo

# Test Nginx configuration
sudo nginx -t

# Restart to ensure everything is loaded
sudo systemctl restart nginx

# Verify HTTPS is working
curl -I https://sftp.yourdomain.com

6. Verify certificate auto-renewal:

# Test renewal
sudo certbot renew --dry-run

# Check auto-renewal timer
sudo systemctl status certbot.timer
# Should show: active (waiting)

7. Verify port 8080 is not publicly accessible:

sudo ufw status | grep 8080
# Should NOT show port 8080 allowed from anywhere

Access your admin panel: https://sftp.yourdomain.com


Option 2: Without Domain Name (Self-Signed Certificate)

⚠️ Browser will show warning (because it's self-signed), but traffic is still encrypted.

1. Install Nginx:

sudo apt install nginx -y

2. Create certificate directory and generate self-signed certificate:

# Create certificate directory
sudo mkdir -p /etc/nginx/ssl

# Generate self-signed certificate (valid 365 days)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/sftpgo.key \
  -out /etc/nginx/ssl/sftpgo.crt \
  -subj "/C=US/ST=State/L=City/O=Organization/CN=your_server_ip"

# Secure the files
sudo chmod 600 /etc/nginx/ssl/sftpgo.key
sudo chmod 644 /etc/nginx/ssl/sftpgo.crt

3. Create Nginx config:

sudo nano /etc/nginx/sites-available/sftpgo

Paste this configuration:

server {
    listen 80;
    server_name _;
    
    # Redirect HTTP to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name _;

    # Self-signed certificate
    ssl_certificate /etc/nginx/ssl/sftpgo.crt;
    ssl_certificate_key /etc/nginx/ssl/sftpgo.key;

    # SSL settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    location / {
        proxy_pass http://localhost:8080;
        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;
        
        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

4. Enable and restart:

sudo ln -s /etc/nginx/sites-available/sftpgo /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx

5. Verify port 8080 is not publicly accessible:

sudo ufw status | grep 8080
# Should NOT show port 8080 allowed from anywhere

Access your admin panel: https://your_server_ip

Note: Browser will show "Not Secure" warning. Click "Advanced" → "Proceed" (or equivalent). Traffic is encrypted, but browser can't verify identity because the certificate is self-signed.


Option 3: SSH Tunnel (Most Secure for Personal Use)

Best for: Solo admin, maximum security, no domain needed, no certificate setup needed.

No Nginx needed! Port 8080 remains blocked from the internet entirely.

From Your Local Machine:

Mac/Linux:

ssh -L 8080:localhost:8080 root@your_server_ip -N

Windows (using PuTTY):

  1. Session → Host: your_server_ip
  2. Connection → SSH → Tunnels:
    • Source port: 8080
    • Destination: localhost:8080
    • Click "Add"
  3. Click "Open"

Then access: http://localhost:8080

Why this is secure:

  • ✅ Traffic encrypted via SSH tunnel
  • ✅ Port 8080 never exposed to internet
  • ✅ No certificates needed
  • ✅ Works without domain
  • ✅ Maximum security

Downside: Must create tunnel each time you need admin access (takes ~5 seconds)

Ensure port 8080 is blocked:

# Verify 8080 is NOT in the firewall rules
sudo ufw status | grep 8080
# If it shows as allowed, you're good since it's already blocked by default

Access your admin panel: http://localhost:8080 (while SSH tunnel is active)


Recommended Setup by Use Case

Scenario Best Option Why
Have domain name Option 1 (Let's Encrypt) Free, trusted certificate, no warnings
No domain, multiple admins Option 2 (Self-signed) HTTPS protection, accessible to team
No domain, solo admin Option 3 (SSH tunnel) Most secure, zero certificate hassle
Temporary/testing Option 3 (SSH tunnel) Quick, no setup needed

4. Create Admin Account

After setting up HTTPS using one of the three options above, open browser and navigate to your secure URL.

You'll see the first-time setup page:

  1. Enter admin username
  2. Create strong password (20+ characters)
  3. Click "Create Admin"
  4. You're in! 🎉

Security Note: Create the admin account immediately after installation. Anyone who accesses the web UI first can create it.


Managing Users (Web Interface)

Create SFTP User

  1. Navigate: Click "Users" → "+" button

  2. Basic Info:

    • Username: company_a
    • Status: ✅ Enabled
    • Password: Leave blank (using SSH keys)
    • Home Dir: /srv/sftpgo/data/company_a
  3. Add SSH Key:

    • Click "Add" in Public keys section
    • Paste the public key:
      ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJl3dIeun... user@example.com
      
  4. Set Permissions (check what you need):

    • ✅ List items
    • ✅ Download
    • ✅ Upload
    • ✅ Overwrite
    • ✅ Delete
    • ✅ Rename
    • ✅ Create dirs
    • ✅ Create symlinks
    • ✅ Delete dirs
    • ✅ Delete files
  5. Quota (optional):

    • Size: 50 GB
    • Files: 10000 files
    • (0 = unlimited)
  6. Bandwidth (optional):

    • Upload: 0 KB/s (unlimited)
    • Download: 0 KB/s (unlimited)
  7. Click Submit

Repeat for Additional Users

Same process for company_b, company_c, etc. Each user gets:

  • ✅ Isolated home directory
  • ✅ Cannot see other users' files
  • ✅ Independent quotas and permissions

Connecting to SFTP

Command Line

sftp -P 2022 -i ~/.ssh/id_ed25519 company_a@your_server_ip

Test operations:

sftp> ls
sftp> mkdir test
sftp> put local_file.txt
sftp> get remote_file.txt
sftp> exit

FileZilla

Setup:

  1. Edit → Settings → SFTP
  2. Add key file (private key)
  3. Click OK

Connect:

  • Host: sftp://your_server_ip
  • Port: 2022
  • Username: company_a
  • Password: (leave blank)
  • Click "Quickconnect"

Connection Details to Share

SFTP Server Connection Info:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Host: your_server_ip
Port: 2022
Username: company_a
Auth: SSH Key Only
Protocol: SFTP

Web UI Management

Daily Admin Tasks

View All Users:

  • Click "Users" in sidebar
  • See login times, disk usage, status

Edit User:

  • Click username
  • Modify any setting
  • Click Submit (takes effect immediately)

Add SSH Key to User:

  • Edit user → Public keys → Add
  • Paste new key → Submit
  • Now both keys work

Revoke SSH Key:

  • Edit user → Find key
  • Click 🗑️ trash icon
  • Submit (immediate revoke)

Monitor Active Connections:

  • Click "Connections"
  • See who's connected right now
  • View active transfers
  • Force disconnect if needed

View Logs:

  • Click "Logs"
  • Filter by user, event type, date
  • See logins, uploads, downloads, errors

Check Disk Usage:

  • Users page shows quota usage
  • Click user for detailed breakdown
  • Manual quota scan available

Advanced Features

Virtual Folders (Shared Directories)

Create shared folder:

  1. Click "Folders" → "+"
  2. Name: shared_documents
  3. Path: /srv/sftpgo/data/shared
  4. Submit

Mount to users:

  1. Edit user → Virtual folders → Add
  2. Select shared_documents
  3. Virtual path: /shared
  4. Set permissions → Submit

Now multiple users can access the same folder!

User Groups

Create group:

  1. Click "Groups" → "+"
  2. Name: premium_clients
  3. Set default quota: 100 GB
  4. Configure default permissions
  5. Submit

Assign users:

  1. Edit user
  2. Select group from dropdown
  3. Submit

Group settings apply automatically to all members.

IP Restrictions

Limit by IP:

  1. Edit user
  2. IP address restrictions section
  3. Allowed IP/Mask: 203.0.113.0/24
  4. Submit

User can only connect from those IPs.

Bandwidth Throttling

Set speed limits:

  1. Edit user
  2. Upload bandwidth: 5120 KB/s (5 MB/s)
  3. Download bandwidth: 10240 KB/s (10 MB/s)
  4. Submit

Event Rules

Automate actions:

  1. Click "Event Manager" → "+"
  2. Set trigger (e.g., "file uploaded")
  3. Add conditions (optional)
  4. Define action:
    • HTTP webhook
    • Execute command
    • Send email
    • Delete files
  5. Submit

Example: Email notification on every upload.


Security Features (Built-in)

Mandatory HTTPS - Admin interface never accessible over HTTP
Chroot Isolation - Users can't escape their directories
SSH Key Auth - No password brute-force attacks
IP Whitelisting - Restrict by location
Bandwidth Limits - Prevent abuse
Quota Enforcement - Automatic disk limits
Audit Logging - Complete activity trail
2FA Support - Optional TOTP
Per-folder Permissions - Granular control


Certificate Management (Option 1 Only)

Let's Encrypt certificates expire every 90 days. Certbot auto-renews them:

# Test renewal (dry run)
sudo certbot renew --dry-run

# Check auto-renewal timer
sudo systemctl status certbot.timer
# Should show: active (waiting)

# Manual renewal (if needed)
sudo certbot renew

# Force renewal (for testing)
sudo certbot renew --force-renewal

Certbot automatically renews certificates when they have 30 days left.

Set up renewal notifications:

# Add to /etc/letsencrypt/renewal-hooks/post/notify.sh
sudo nano /etc/letsencrypt/renewal-hooks/post/notify.sh

Add:

#!/bin/bash
echo "SSL certificate renewed successfully" | \
mail -s "SSL Certificate Renewed" admin@yourdomain.com

Make executable:

sudo chmod +x /etc/letsencrypt/renewal-hooks/post/notify.sh

Troubleshooting

Can't Access Web UI

# Check SFTPGo service status
sudo systemctl status sftpgo

# Restart service
sudo systemctl restart sftpgo

# Check Nginx status (if using Options 1 or 2)
sudo systemctl status nginx
sudo nginx -t  # Test configuration

# Check firewall
sudo ufw status

# View SFTPGo logs
sudo journalctl -u sftpgo -n 50 --no-pager

# View Nginx logs (if using Options 1 or 2)
sudo tail -f /var/log/nginx/error.log
sudo tail -f /var/log/nginx/access.log

SSL Certificate Issues (Option 1)

# Check certificate expiry
sudo certbot certificates

# Test renewal
sudo certbot renew --dry-run

# Force renewal
sudo certbot renew --force-renewal

# Check Nginx SSL config
sudo nginx -t

Forgot Admin Password

# Reset password
sudo sftpgo resetpwd --admin admin

# Enter new password when prompted

SFTP Connection Refused

# Verify SFTPGo is listening on port 2022
sudo ss -tlnp | grep 2022

# Check firewall allows 2022
sudo ufw status | grep 2022

# Test from server
sftp -P 2022 username@localhost

User Can't Login

Check in web UI:

  1. User is enabled
  2. SSH key is correctly added (no extra spaces)
  3. Home directory path is correct
  4. No IP restrictions blocking them

Check logs:

  • Web UI → Logs → Filter by username

Quota Not Updating

# Trigger manual quota scan
# In web UI: Edit user → Click "Quota scan" button

# Or via command line
sudo sftpgo quota-scan --username company_a

Useful Commands

# Service management
sudo systemctl status sftpgo
sudo systemctl restart sftpgo
sudo systemctl stop sftpgo
sudo systemctl start sftpgo

# Nginx service (if using Options 1 or 2)
sudo systemctl status nginx
sudo systemctl restart nginx
sudo nginx -t  # Test configuration

# View logs
sudo journalctl -u sftpgo -f              # Follow logs
sudo journalctl -u sftpgo -n 100          # Last 100 lines
sudo journalctl -u sftpgo --since today   # Today's logs

# Check config
sudo cat /etc/sftpgo/sftpgo.json

# Data directory
ls -lah /srv/sftpgo/data/

# Check port usage
sudo ss -tlnp | grep -E '2022|8080|443'

Backup Strategy

Important files to backup:

# User database and config
/var/lib/sftpgo/
/etc/sftpgo/

# User data
/srv/sftpgo/data/

# SSL certificates (if using Option 2)
/etc/nginx/ssl/

# Let's Encrypt (if using Option 1)
/etc/letsencrypt/

Simple backup script:

#!/bin/bash
BACKUP_DIR="/backup/sftpgo/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

# Stop service
sudo systemctl stop sftpgo

# Backup
sudo cp -r /var/lib/sftpgo "$BACKUP_DIR/"
sudo cp -r /etc/sftpgo "$BACKUP_DIR/"
sudo cp -r /srv/sftpgo/data "$BACKUP_DIR/"

# Backup SSL (if applicable)
[ -d /etc/letsencrypt ] && sudo cp -r /etc/letsencrypt "$BACKUP_DIR/"
[ -d /etc/nginx/ssl ] && sudo cp -r /etc/nginx/ssl "$BACKUP_DIR/"

# Start service
sudo systemctl start sftpgo

echo "Backup completed: $BACKUP_DIR"

Cost Comparison

Solution Monthly Cost Annual Cost
SFTPGo (Self-hosted) $12 $144
Azure Blob SFTP $220+ $2,640+
AWS Transfer Family $216+ $2,592+
Your Savings $208/month $2,496/year

Security Best Practices

NEVER Do This:

  • ❌ Access admin panel over HTTP
  • ❌ Leave port 8080 open to public
  • ❌ Use weak passwords
  • ❌ Ignore certificate expiration warnings
  • ❌ Share credentials between companies
  • ❌ Disable SSL/TLS

ALWAYS Do This:

  • ✅ Use HTTPS for all admin access (one of the three secure methods)
  • ✅ Use strong, unique passwords (20+ characters, mixed case, numbers, symbols)
  • ✅ Enable 2FA if SFTPGo supports it (check latest version)
  • ✅ Restrict admin access by IP when possible
  • ✅ Monitor access logs regularly
  • ✅ Keep SSL certificates up to date (Option 1 auto-renews)
  • ✅ Regular backups of SFTPGo configuration
  • ✅ Test disaster recovery procedures
  • ✅ Keep system and SFTPGo updated

Why SFTPGo?

Pros:

  • ✅ Web-based management (no CLI needed)
  • ✅ Multi-tenant with isolation
  • ✅ SSH key authentication
  • ✅ Quota management
  • ✅ Real-time monitoring
  • ✅ Free and open source
  • ✅ Active development
  • ✅ Extensive documentation
  • ✅ API for automation
  • ✅ Cost-effective ($12/month)
  • ✅ Secure HTTPS options built-in

Cons:

  • ⚠️ Requires server management
  • ⚠️ You handle backups
  • ⚠️ You handle updates
  • ⚠️ No built-in redundancy (single server)

Perfect for:

  • Companies sharing files with clients
  • Agencies managing client uploads
  • SaaS apps needing SFTP integration
  • Replacing expensive managed SFTP services
  • Teams that need web-based management

Next Steps

Enhance Security:

  • Verify HTTPS is working correctly
  • Enable 2FA for admin account
  • Set up automated backups
  • Implement IP whitelisting
  • Configure fail2ban for brute-force protection

Scale Up:

  • Move to PostgreSQL/MySQL for larger deployments
  • Set up multiple SFTPGo instances with load balancer
  • Integrate with LDAP/Active Directory
  • Configure S3/Azure Blob as storage backend
  • Set up monitoring with Prometheus/Grafana

Automate:

  • Use SFTPGo REST API for user provisioning
  • Set up event rules for automated workflows
  • Create scripts for bulk user management
  • Integrate with your billing system

Resources


Quick Reference Card

# Installation
sudo add-apt-repository ppa:sftpgo/sftpgo && sudo apt update && sudo apt install sftpgo -y

# Set up HTTPS first (see HTTPS Setup section)

# Web UI (choose your secure method)
https://sftp.yourdomain.com          # Option 1
https://your_server_ip               # Option 2
http://localhost:8080                # Option 3 (via SSH tunnel)

# SFTP Connection
sftp -P 2022 -i ~/.ssh/key username@your_server_ip

# Service Commands
sudo systemctl {start|stop|restart|status} sftpgo
sudo systemctl {start|stop|restart|status} nginx  # If using Options 1 or 2

# Logs
sudo journalctl -u sftpgo -f
sudo tail -f /var/log/nginx/error.log  # If using Options 1 or 2

# Reset Admin Password
sudo sftpgo resetpwd --admin admin

# Quota Scan
sudo sftpgo quota-scan --username username

# SSL Certificate (Option 1)
sudo certbot renew --dry-run
sudo certbot certificates

Setup time: ~30-45 minutes (including HTTPS)
Learning curve: Low (web interface)
Maintenance: Minimal (mainly OS updates)
Security: Production-ready with mandatory HTTPS

Enjoy your cost-effective, professional, secure SFTP server! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment