Fetching latest headlines…
Deploying SFTPGo as an AWS Transfer Family Alternative on Ubuntu
NORTH AMERICA
πŸ‡ΊπŸ‡Έ United Statesβ€’July 2, 2026

Deploying SFTPGo as an AWS Transfer Family Alternative on Ubuntu

0 views0 likes0 comments
Originally published byDev.to

SFTPGo is an open-source file transfer server that exposes SFTP, FTP/S, and WebDAV with pluggable storage backends and a web admin UI, a self-hosted alternative to AWS Transfer Family without per-endpoint billing. This guide deploys SFTPGo using Docker Compose with Traefik handling automatic HTTPS for the admin UI, SQLite for the data provider, and protocol ports for SFTP, FTP/S, and WebDAV exposed on the host. By the end, you'll have SFTPGo accepting multi-protocol file transfers backed by either local disk or S3-compatible object storage.

Set Up the Directory Structure

1. Create the project directories:

$ mkdir -p ~/sftpgo/{data,config}
$ cd ~/sftpgo

2. Create the environment file:

$ nano .env
DOMAIN=sftp.example.com
LETSENCRYPT_EMAIL=[email protected]

Deploy with Docker Compose

1. Create the Compose manifest:

$ nano docker-compose.yml
services:
  traefik:
    image: traefik:v3.6
    container_name: traefik
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
      - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    restart: unless-stopped

  sftpgo:
    image: drakkan/sftpgo:v2.6
    container_name: sftpgo
    restart: unless-stopped
    ports:
      - "2022:2022"   # SFTP
      - "2121:2121"   # FTP/S control
      - "10080:10080" # WebDAV
    environment:
      - SFTPGO_HTTPD__BINDINGS__0__PORT=8080
      - SFTPGO_HTTPD__BINDINGS__0__ADDRESS=0.0.0.0
      - SFTPGO_SFTPD__BINDINGS__0__PORT=2022
      - SFTPGO_FTPD__BINDINGS__0__PORT=2121
      - SFTPGO_WEBDAVD__BINDINGS__0__PORT=10080
      - SFTPGO_DATA_PROVIDER__DRIVER=sqlite
      - SFTPGO_DATA_PROVIDER__NAME=/var/lib/sftpgo/sftpgo.db
    volumes:
      - ./data:/srv/sftpgo
      - ./config:/var/lib/sftpgo
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.sftpgo.rule=Host(`${DOMAIN}`)"
      - "traefik.http.routers.sftpgo.entrypoints=websecure"
      - "traefik.http.routers.sftpgo.tls.certresolver=letsencrypt"
      - "traefik.http.services.sftpgo.loadbalancer.server.port=8080"
    healthcheck:
      test: ["CMD", "sftpgo", "ping", "-c", "/var/lib/sftpgo"]
      interval: 30s
      timeout: 10s
      retries: 3

2. Start the services and view logs:

$ docker compose up -d
$ docker compose ps
$ docker compose logs

Initial Admin Setup

  1. Open https://sftp.example.com/web/admin.
  2. Create the administrator account.
  3. Enable two-factor authentication, scan the QR code with an authenticator app, and save the recovery codes.

Enable the Defender (Brute-Force Protection)

Edit docker-compose.yml and add to the sftpgo service environment: block:

- SFTPGO_COMMON__DEFENDER__ENABLED=true
- SFTPGO_COMMON__DEFENDER__DRIVER=memory
- SFTPGO_COMMON__DEFENDER__BAN_TIME=30
- SFTPGO_COMMON__DEFENDER__THRESHOLD=15
- SFTPGO_COMMON__DEFENDER__SCORE_INVALID=2
- SFTPGO_COMMON__DEFENDER__SCORE_VALID=1

Redeploy:

$ docker compose up -d

Trusted IPs go under IP Manager β†’ IP Lists; auto-banned IPs appear under Auto Block List.

Create a User (Password + SSH Key)

  1. Users β†’ Add: username, password, status Active, file system Local disk, root directory /srv/sftpgo/USERNAME.
  2. (Optional) Generate an SSH key on a client:
$ ssh-keygen -t ed25519 -f ~/.ssh/sftpgo_key -C "sftp-user"
$ cat ~/.ssh/sftpgo_key.pub
  1. Users β†’ Edit β†’ Public keys β€” paste the public key.
  2. Test:
$ sftp -i ~/.ssh/sftpgo_key -P 2022 [email protected]
  1. (Optional) Require 2FA per-protocol under Edit β†’ ACLs β†’ Require 2FA for.

Connect S3-Compatible Object Storage

In the user's Edit β†’ File system block:

  • File system: S3 (Compatible)
  • Bucket: BUCKET_NAME
  • Region: REGION_CODE
  • Access Key / Access Secret: S3 credentials
  • Endpoint: https://YOUR_S3_ENDPOINT
  • Use path-style addressing: enabled
  • Upload Part Size: 5 MB Β· Upload Concurrency: 2

Save and round-trip a test file:

$ echo "Hello SFTPGo" > testfile.txt
$ sftp -P 2022 [email protected]
sftp> put testfile.txt
sftp> ls
sftp> exit

S3 caveats: resume uploads disabled, no symlinks, non-atomic directory rename, chmod/chown ignored.

Enable FTP/S and WebDAV

1. Generate a self-signed cert for FTP/S:

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout ~/sftpgo/config/server.key \
    -out ~/sftpgo/config/server.crt \
    -subj "/CN=sftp.example.com"

2. Create the SFTPGo JSON config:

$ nano ~/sftpgo/config/sftpgo.json
{
  "ftpd": {
    "bindings": [
      {
        "port": 2121,
        "address": "",
        "tls_mode": 1,
        "certificate_file": "/var/lib/sftpgo/server.crt",
        "certificate_key_file": "/var/lib/sftpgo/server.key"
      }
    ],
    "passive_port_range": {"start": 50000, "end": 50100}
  },
  "webdavd": {
    "bindings": [
      {"port": 10080, "address": "", "enable_https": false}
    ]
  }
}

3. Expose the passive port range in docker-compose.yml:

- "50000-50100:50000-50100"

4. Restart and test:

$ docker compose restart sftpgo
$ lftp -u USERNAME -p 2121 ftp://sftp.example.com
$ curl -u USERNAME:PASSWORD http://sftp.example.com:10080/

Add Quotas, Bandwidth Limits, and IP ACLs

Per-user Edit β†’ Disk quota and bandwidth limits:

  • Quota size: 10GB (0 = unlimited) Β· Quota files: 10000
  • Bandwidth UL/DL (KB/s): e.g. 5120 for 5 MB/s

Per-user ACLs:

  • Allowed IP/Mask: 192.168.1.0/24, 10.0.0.0/8
  • Denied IP/Mask: specific blocked addresses
  • Per-directory permissions: restrict each path's operations

File Logging and Webhooks

1. Enable file logging:

$ mkdir -p ~/sftpgo/logs

Add to the sftpgo service:

volumes:
  - ./logs:/var/log/sftpgo
environment:
  - SFTPGO_LOG_FILE_PATH=/var/log/sftpgo/sftpgo.log
  - SFTPGO_LOG_MAX_SIZE=10
  - SFTPGO_LOG_MAX_BACKUPS=5
  - SFTPGO_LOG_MAX_AGE=28
  - SFTPGO_LOG_LEVEL=info
$ docker compose up -d

2. Set up webhook notifications:

  • Event Manager β†’ Actions β†’ Add: HTTP, set the server URL and POST method.
  • Event Manager β†’ Rules β†’ Add: trigger on filesystem events (e.g. Upload) and attach the webhook action.

Next Steps

SFTPGo is running with multi-protocol access and HTTPS for the admin UI. From here you can:

  • Plug an external Postgres or MySQL backend by switching the data provider env vars
  • Generate user API tokens and provision accounts via the REST API for migrations
  • Front the SFTP port with a VPN (WireGuard) for tighter network isolation

For the full guide with additional tips, visit the original article on Vultr Docs.

Comments (0)

Sign in to join the discussion

Be the first to comment!