Azure Storage SFTP is Microsoft’s managed file transfer service on top of Azure Blob Storage, convenient, but billed continuously per endpoint (roughly $0.30/hour, ~$220/month) and tied to Azure AD. SFTPGo is an open-source file transfer server offering SFTP, FTP/S, and WebDAV with pluggable storage backends (local disk, Azure Blob, S3-compatible, GCS) and no per-endpoint charge. This guide deploys SFTPGo with Docker Compose and Traefik, sets up user auth (password + SSH key + 2FA), connects S3-compatible object storage, and covers the migration path from Azure Storage SFTP. By the end, you’ll have a self-hosted file transfer server with the same capabilities at zero endpoint cost.
Azure Storage SFTP → SFTPGo Mapping
Azure Storage SFTP SFTPGo Equivalent Notes SFTP Endpoint SFTPGo SFTP Server Configurable port, default2022
Azure Blob Storage
Azure Blob backend
Native support; point at the same container, no migration needed
Azure AD Authentication
LDAP/OIDC plugin
External identity provider via plugin
Local Users
Web UI / REST API user management
Hierarchical Namespace
Virtual directories
No HNS requirement
Azure Monitor
Built-in logging + webhooks/syslog
Prerequisite: Linux server with Docker + Compose, a DNS A record for your domain, and (if migrating) an existing Azure Storage account with SFTP enabled plus the Azure CLI installed locally.
Deploy with Docker Compose
1. Create the project directories:
$ mkdir -p ~/sftpgo/{data,config}
$ cd ~/sftpgo
Enter fullscreen mode Exit fullscreen mode
2. Create the environment file:
$ nano .env
Enter fullscreen mode Exit fullscreen mode
DOMAIN=sftp.example.com
[email protected]
Enter fullscreen mode Exit fullscreen mode
3. Create the Compose manifest:
$ nano docker-compose.yml
Enter fullscreen mode Exit fullscreen mode
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.7
container_name: sftpgo
restart: unless-stopped
ports:
- "2022:2022"
- "2121:2121"
- "10080:10080"
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
volumes:
letsencrypt:
Enter fullscreen mode Exit fullscreen mode
Traefik terminates TLS on 80/443 for the admin UI; SFTP/FTP/S/WebDAV listen directly on 2022/2121/10080. Port 8080 (the admin UI’s internal port) is never exposed to the host — Traefik proxies to it over the Docker network.
4. Start the stack:
$ docker compose up -d
$ docker compose ps
$ docker compose logs
Enter fullscreen mode Exit fullscreen mode
Initial Admin Setup
- Open
https://sftp.example.com/web/admin. - Create the administrator: username, strong password, confirm, Create admin and Sign in.
- Review Server Manager → Configurations — check the SFTP, ACME, and SMTP sections match your requirements.
Create a User and Configure Authentication
1. Password auth: Users → Add — username, password, Status: Active, File system: Local disk, Root directory: /srv/sftpgo/USERNAME. Save.
2. SSH key auth (passwordless, mirrors Azure’s SSH key support):
$ ssh-keygen -t ed25519 -f ~/.ssh/sftpgo_key -C "sftp-user"
$ cat ~/.ssh/sftpgo_key.pub
Enter fullscreen mode Exit fullscreen mode
Paste the public key into Users → Edit → Public keys, then test:
$ sftp -i ~/.ssh/sftpgo_key -P 2022 [email protected]
Enter fullscreen mode Exit fullscreen mode
3. 2FA: Users → Edit → ACLs → Require 2FA for — select the protocols to gate. The user sets up their authenticator app on next WebClient login.
Connect S3-Compatible Object Storage
SFTPGo supports Azure Blob directly, but also any S3-compatible provider — useful if you’re consolidating storage away from Azure.
- Gather your endpoint URL, access key, secret key, and bucket name from the provider.
- Users → Edit → File system → Storage: S3 (Compatible).
- Fill in Bucket, Region, Access Key, Access Secret, Endpoint (full URL).
- Enable Use path-style addressing.
- Save, then verify:
$ echo "Hello SFTPGo" > testfile.txt
$ sftp -P 2022 [email protected]
sftp> put testfile.txt
sftp> ls
sftp> exit
Enter fullscreen mode Exit fullscreen mode
S3 backend limitations: resume uploads disabled, no symlinks, non-atomic directory rename,
chmod/chownsilently ignored.
Test All Protocols
$ echo "Hello SFTPGo" > testfile.txt
$ sftp -P 2022 [email protected]
sftp> put testfile.txt
sftp> get testfile.txt /tmp/testfile-downloaded.txt
sftp> exit
$ sftp -i ~/.ssh/sftpgo_key -P 2022 [email protected]
$ sudo apt install lftp -y
$ lftp -u USERNAME -p 2121 ftp://sftp.example.com
lftp> ls
lftp> exit
Enter fullscreen mode Exit fullscreen mode
Migrate from Azure Storage SFTP
Export Users
$ az storage account local-user list --account-name STORAGE_ACCOUNT --resource-group RESOURCE_GROUP
$ az storage account local-user show --account-name STORAGE_ACCOUNT --resource-group RESOURCE_GROUP --name USERNAME
Enter fullscreen mode Exit fullscreen mode
Record username, SSH public keys, home directory (container + path), and permission scope for each user.
Recreate Users in SFTPGo
$ curl -u ADMIN_USERNAME:ADMIN_PASSWORD https://sftp.example.com/api/v2/token
Enter fullscreen mode Exit fullscreen mode
Copy the access_token — it expires in 15 minutes.
$ curl -X POST "https://sftp.example.com/api/v2/users" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "USERNAME",
"password": "PASSWORD",
"status": 1,
"public_keys": ["SSH_PUBLIC_KEY"],
"home_dir": "/srv/sftpgo/data/USERNAME",
"permissions": {"/": ["*"]}
}'
Enter fullscreen mode Exit fullscreen mode
"status": 1 is required — without it the account is created disabled.
Migrate Data
If SFTPGo will use Azure Blob as its own backend, just point users at the same container — no data transfer needed. For local-disk backends, pull the data down:
$ az storage blob download-batch --account-name STORAGE_ACCOUNT --source CONTAINER_NAME --destination ~/sftpgo/data/USERNAME/
$ sudo chown -R 1000:1000 ~/sftpgo/data/
Enter fullscreen mode Exit fullscreen mode
Map Authentication Methods
Azure Method SFTPGo Equivalent SSH Public Keys Public Keys (direct) Local User Passwords Password Authentication Azure AD (Preview) LDAP/OIDC plugin, or external auth hookUpdate Clients
Document the new endpoint (sftp.example.com, port 2022, SSH key or password) and roll it out before decommissioning the Azure endpoint. Export SFTPGo’s SSH host key (/var/lib/sftpgo/id_*) and share the fingerprint so clients don’t hit host-key warnings.
Things to Watch
- Hierarchical Namespace: Azure Storage SFTP requires HNS; SFTPGo simulates directories without it — check any app that depends on HNS-specific behavior.
- Container-level permissions: map to SFTPGo’s per-directory ACLs.
- Lifecycle policies: SFTPGo doesn’t manage Azure Blob lifecycle rules — keep configuring those in Azure if you stay on the Blob backend.
- Azure Monitor: replace with SFTPGo’s logging, syslog, or webhook integrations.
Next Steps
SFTPGo is running as a self-hosted Azure Storage SFTP replacement with zero per-endpoint charge. From here you can:
- Enable the Azure Blob backend directly if you want to keep data in place
- Set quotas, bandwidth limits, and IP ACLs per user under Edit → Disk quota / ACLs
- Wire event hooks (webhooks/syslog) to replace Azure Monitor alerting
For the full guide with additional tips, visit the original article on Vultr Docs.
답글 남기기