File: README.md
SFTPGo
Full-featured and highly configurable event-driven file transfer solution. Server protocols: SFTP, HTTP/S, FTP/S, WebDAV. Storage backends: local filesystem, encrypted local filesystem, S3 (compatible) Object Storage, Google Cloud Storage, Azure Blob Storage, other SFTP servers.
With SFTPGo you can leverage local and cloud storage backends for exchanging and storing files internally or with business partners using the same tools and processes you are already familiar with.
Project Status & Editions
SFTPGo is an open-source project with a sustainable business model. We offer two editions to suit different requirements, ensuring the project remains healthy and maintained for everyone.
Open Source (Community)
Free, Copyleft (AGPLv3), Community Supported. The Community edition is a fully functional, production-ready solution widely adopted worldwide. It includes all the core protocols, storage backends, and the WebAdmin/WebClient UIs. It is ideal for:
- Standard file transfer needs.
- Integrating storage backends (S3, GCS, Azure Blob) with legacy protocols.
- Projects that are comfortable with AGPLv3 licensing.
SFTPGo Enterprise
Commercial License, Professional Support, ISO 27001 Vendor. The Enterprise edition is built on the same core but extends it for mission-critical environments, compliance-heavy industries, and advanced workflows. It is a drop-in replacement (seamless upgrade).
| Feature | Open Source (Community) | Enterprise Edition |
|---|---|---|
| License Type | AGPLv3 (Copyleft) | Commercial LicenseProprietary/No Copyleft |
| Vendor Compliance | Not ApplicableCommunity Project | Certified VendorISO 27001 & Supply Chain Validation |
| Support | Community (GitHub) | Direct from Authors |
| Cloud Storage Engine | Standard | High Performance & ScalableIn-memory streaming (no local temp files) and up to 70% faster |
| High Availability (HA) | StandardShared DB & Storage | AdvancedEnhanced event handling and optimized instance coordination |
| Automation Logic | Simple Placeholders | Dynamic Logic & Virtual FoldersConditions, loops, route data across storage backends |
| Data Lifecycle | Delete / Retain | Smart ArchivingMove data to external Cloud/SFTP storage via Virtual Folders |
| Email Data Ingestion | - | Native IMAP IntegrationAuto-extract attachments from email to storage |
| Public Sharing | Standard Links | Advanced & CollaborativeEmail Authentication & Group Delegation |
| Data Protection | - | Encryption & ScanningAutomated PGP, Antivirus & DLP via ICAP |
| Advanced Identity (SSO) | Standard | Extended ControlsAdvanced Single Sign-On parameters |
| Document Editing | - | IncludedView, edit, and co-author in browser |
Note: We are committed to keeping the Open Source edition powerful and maintained. The Enterprise edition helps fund the development of the entire SFTPGo ecosystem.
Sponsors
If you rely on SFTPGo in your projects, consider becoming a sponsor.
Your sponsorship helps cover maintenance, security updates and ongoing development of the open-source edition.
Thank you to our sponsors
Platinum sponsors
Silver sponsors
Bronze sponsors
Documentation
You can explore all supported features and configuration options at docs.sftpgo.com.
Note: The link above refers to the Community Edition.
For details on Enterprise Edition, please refer to the Enterprise Documentation.
Support
- Community Support: use GitHub Discussions to ask questions, share feedback, and engage with other users.
- Commercial Support: If you require guaranteed SLAs, expert guidance, or the advanced features listed above, check out SFTPGo Enterprise.
SFTPGo Enterprise is available as:
- On-premises: Full control on your infrastructure. More details: sftpgo.com/on-premises
- Fully managed SaaS: We handle the infrastructure. More details: sftpgo.com/saas
Internationalization
The translations are available via Crowdin, who have granted us an open source license.
Before translating please take a look at our contribution guidelines.
Release Cadence
SFTPGo follows a feature-driven release cycle.
- Enterprise Edition: Receives major new features first and follows a faster release cadence.
- Community Edition: Remains maintained, receiving bug fixes, security updates, and updates to core features.
Acknowledgements
SFTPGo makes use of the third party libraries listed inside go.mod.
We are very grateful to all the people who contributed with ideas and/or pull requests.
Thank you to ysura for granting us stable access to a test AWS S3 account.
Thank you to KeenThemes for granting us a custom license to use their amazing themes for the SFTPGo WebAdmin and WebClient user interfaces, across both the Open Source and Open Core versions.
Thank you to Crowdin for granting us an Open Source License.
Thank you to Incode for helping us to improve the UI/UX.
License
SFTPGo source code is licensed under the GNU AGPL-3.0-only with additional terms.
The theme used in WebAdmin and WebClient user interfaces is proprietary, this means:
- KeenThemes HTML/CSS/JS components are allowed for use only within the SFTPGo product and restricted to be used in a resealable HTML template that can compete with KeenThemes products anyhow.
- The SFTPGo WebAdmin and WebClient user interfaces (HTML, CSS and JS components) based on this theme are allowed for use only within the SFTPGo product and therefore cannot be used in derivative works/products without an explicit grant from the SFTPGo Team.
More information about compliance.
Note: We do not provide legal advice. If you have questions about license compliance or whether your use case is permitted under the license terms, please consult your legal team.
Copyright
Copyright (C) 2019 - 2026 Nicola Murino
File: examples/quotascan/README.md
Update user quota
:warning: Since v2.4.0 you can use the EventManager to schedule quota scans.
The scanuserquota example script shows how to use the SFTPGo REST API to update the users' quota.
The stored quota may be incorrect for several reasons, such as an unexpected shutdown while uploading files, temporary provider failures, files copied outside of SFTPGo, and so on.
A quota scan updates the number of files and their total size for the specified user and the virtual folders, if any, included in his quota.
If you want to track quotas, a scheduled quota scan is recommended. You can use this example as a starting point.
The script is written in Python and has the following requirements:
- python3 or python2
- python Requests module
The provided example tries to connect to an SFTPGo instance running on 127.0.0.1:8080 using the following credentials:
- username:
admin - password:
password
Please edit the script according to your needs.
File: examples/php-activedirectory-http-server/README.md
SFTPGo on Windows with Active Directory Integration + Caddy Static File Server Example
This is similar to the ldapauthserver example, but is more specific to using Active Directory along with using SFTPGo on a Windows Server.
The Youtube Walkthrough/Tutorial video above goes into considerable more detail, but in short, it walks through setting up SFTPGo on a new Windows Server, and enables the External Authentication feature within SFTPGo, along with my sftpgo-ldap-http-server project, to allow for user authentication into SFTPGo to occur through one or more Active Directory connections.
Additionally, I go through using the Caddy web server, to help enable serving of static files, if this is something that would be of interest for you.
To get started, you'll want to download the latest release ZIP package from the sftpgo-ldap-http-server repository.
The ZIP itself contains the sftpgo-ldap-http-server.exe file, along with an OpenLDAP folder (mainly to help if you want to use TLS for your LDAP connections), and a Data which contains a logs folder, a configuration.example.php file, a functions.php file, and the LICENSE and README files.
The video above goes through the whole process, but to get started you'll want to install SFTPGo on your server, and then extract the sftpgo-ldap-http-server ZIP file on the server as well into a separate folder. Then you'll want to copy the configuration.example.php file and name it configuration.php and begin customizing the settings (e.g. add in your own LDAP settings, along with how you may want to have your folders be created). At the very minimum you'll want to make sure that the home directories are set correctly to how you want the folders to be created for your environment (you don't have to use the virtual folders or really any of the other functionality if you don't need it).
Once configured, from a command prompt window, if you are already in the same folder as where you extracted the sftpgo-ldap-http-server ZIP, you may simply call the sftpgo-ldap-http-server.exe and it should start up a simple HTTP server on Port 9001 running on localhost (the port can be adjusted via the configuration.php file as well). Now all you have to do is point SFTPGo's external_auth_hook option to point to http://localhost:9001/ and you should be able to run some authentication tests (assuming you have all of your settings correct and there are no intermediate issues).
The video above definitely goes through some troubleshooting situations you might find yourself coming across, so while it is long (at about 1 hour, 42 minutes), it may be helpful to review and avoid some issues and just to learn a bit more about SFTPGo and the integration above.
Example Virtual Folders Configuration (Allowing for Both a Public and Private Folder)
The following can be utilized if you'd like to assign your users both a Private Virtual Folder and Public Virtual Folder.
By itself, the Public Virtual Folder isn't necessarily public, so keep that in mind. Only by combining things together with the Caddy web server (and Caddyfile example configuration down below) can you be successful in making the F:\files\public folder from the example public.
$virtual_folders['example'] = [
[
//"id" => 0,
"name" => "private-#USERNAME#",
"mapped_path" => 'F:\files\private\#USERNAME#',
//"used_quota_size" => 0,
//"used_quota_files" => 0,
//"last_quota_update" => 0,
"virtual_path" => "/_private",
"quota_size" => -1,
"quota_files" => -1
],
[
//"id" => 0,
"name" => "public-#USERNAME#",
"mapped_path" => 'F:\files\public\#USERNAME#',
//"used_quota_size" => 0,
//"used_quota_files" => 0,
//"last_quota_update" => 0,
"virtual_path" => "/_public",
"quota_size" => -1,
"quota_files" => -1
]
];Example Connection "Output Object" Allowing For No Files in the User's Home Directory ("Root Directory") but Allowing for Files in the Public/Private Virtual Folders
The magic here happens in the "permissions" value, by limiting the root/home directory to just the list/download permissions, and then allowing all permissions on the Public/Private virtual folders.
$connection_output_objects['example'] = [
'status' => 1,
'username' => '',
'expiration_date' => 0,
'home_dir' => '',
'uid' => 0,
'gid' => 0,
'max_sessions' => 0,
'quota_size' => 0,
'quota_files' => 100000,
'permissions' => [
"/" => ["list", "download"],
"/_private" => ["*"],
"/_public" => ["*"],
],
'upload_bandwidth' => 0,
'download_bandwidth' => 0,
'filters' => [
'allowed_ip' => [],
'denied_ip' => [],
],
'public_keys' => [],
];Recommended Usage of Automatic Groups Mode (Limiting by Group Prefix)
The sftpgo-ldap-http-server project is able to automatically create virtual folders for any groups your user is a memberof if the automatic mode is turned on. However, by having a specific set of allowed prefixes defined, you can limit things to just those groups that begin with the prefixes you've listed, which can be helpful. The prefix itself will be removed from the group name when added as a virtual folder for the user.
// If automatic groups mode is disabled, then you have to manually add the allowed groups into $allowed_groups down below:
// If enabled, then any groups you are a memberof will automatically be added in using the template below.
$auto_groups_mode = true;
$auto_groups_mode_virtual_folder_template = [
[
//"id" => 0,
"name" => "groups-#GROUP#",
"mapped_path" => 'F:\files\groups\#GROUP#',
//"used_quota_size" => 0,
//"used_quota_files" => 0,
//"last_quota_update" => 0,
"virtual_path" => "/groups/#GROUP#",
"quota_size" => 0,
"quota_files" => 100000
]
];
// Used only when auto groups mode is enabled and will help prevent all your groups from being
// added into SFTPGo since only groups with the prefixes defined here will be automatically added
// with prefixes automatically removed when listed as a virtual folder (e.g. a group with name
// "sftpgo-example" would simply become "example").
$allowed_group_prefixes = [
'sftpgo-'
];Example Caddyfile Configuration You Can Adapt for Your Needs
### Re-usable snippets:
(add_static_file_serving_features) {
# Allow accessing files without requiring .html:
try_files {path} {path}.html
# Enable Static File Server and Directory Browsing:
file_server browse
# Enable templating functionality:
templates
# Enable Compression for Output:
encode zstd gzip
handle_errors {
respond "{http.error.status_code} {http.error.status_text}"
}
}
(add_hsts_headers) {
header {
# Enable HTTP Strict Transport Security (HSTS) to force clients to always
# connect via HTTPS (do not use if only testing)
Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Enable cross-site filter (XSS) and tell browser to block detected attacks
X-XSS-Protection "1; mode=block"
# Prevent some browsers from MIME-sniffing a response away from the declared Content-Type
X-Content-Type-Options "nosniff"
# Disallow the site to be rendered within a frame (clickjacking protection)
X-Frame-Options "DENY"
# keep referrer data off of HTTP connections
Referrer-Policy no-referrer-when-downgrade
}
}
(add_logging_with_path) {
log {
output file "{args.0}" {
roll_size 100mb
roll_keep 5
roll_keep_for 720h
}
format json
#format console
#format single_field common_log
}
}
### Site Definitions:
public.example.com {
# Site Root:
root * F:\files\public
import add_logging_with_path "F:\caddy\logs\public_example_com_access.log"
import add_static_file_serving_features
import add_hsts_headers
}
### Reverse Proxy Definitions:
webdav.example.com {
reverse_proxy localhost:9000
import add_logging_with_path "F:\caddy\logs\webdav_example_com_access.log"
}File: examples/OTP/authy/keyint/README.md
Authy 2FA using keyboard interactive authentication
This example shows how to authenticate SFTP users using 2FA (password + Authy token). Please read the sample code, it should be self explanatory.
File: examples/OTP/authy/extauth/README.md
Authy external authentication
This example shows how to use Authy TOTP token as password for SFTPGo users. Please read the sample code, it should be self explanatory.
File: examples/OTP/authy/checkpwd/README.md
Authy 2FA via check password hook
This example shows how to use 2FA via the check password hook using a password consisting of a fixed part and an Authy TOTP token. The hook will check the TOTP token using the Authy API and SFTPGo will check the fixed part. Please read the sample code, it should be self explanatory.
File: examples/OTP/authy/README.md
Authy
These example show how-to integrate Twilio Authy API for One-Time-Password logins.
The examples assume that the user has the free Authy app installed and uses it to generate offline TOTP codes (soft tokens).
You first need to create an Authy Application in the Twilio Console, then you can create a new Authy user and store a reference to the matching SFTPGo account.
Verify that your Authy application is successfully registered:
export AUTHY_API_KEY=<your api key here>
curl 'https://api.authy.com/protected/json/app/details' -H "X-Authy-API-Key: $AUTHY_API_KEY"now create an Authy user:
curl -XPOST "https://api.authy.com/protected/json/users/new" \
-H "X-Authy-API-Key: $AUTHY_API_KEY" \
--data-urlencode user[email]="[email protected]" \
--data-urlencode user[cellphone]="317-338-9302" \
--data-urlencode user[country_code]="54"The response is something like this:
{"message":"User created successfully.","user":{"id":xxxxxxxx},"success":true}Save the user id somewhere and add a reference to the matching SFTPGo account. You could also store this ID in the additional_info SFTPGo user field.
After this step you can use the Authy app installed on your phone to generate TOTP codes.
Now you can verify the token using an HTTP GET request:
export TOKEN=<TOTP you read from Authy app>
export AUTHY_ID=
curl -i "https://api.authy.com/protected/json/verify/${TOKEN}/${AUTHY_ID}" \
-H "X-Authy-API-Key: $AUTHY_API_KEY"So inside your hook you need to check:
- the HTTP response code for the verify request, it must be
200 - the JSON response body, it must contains the key
successwith the valuetrue(as string)
If these conditions are met the token is valid and you allow the user to login.
We provide the following examples:
- Keyboard interactive authentication for 2FA using password + Authy one time token.
- External authentication using Authy one time tokens as passwords.
- Check password hook for 2FA using a password consisting of a fixed string and a One Time Token.
Please note that these are sample programs not intended for production use, you should write your own hook based on them and you should prefer HTTP based hooks if performance is a concern.
:warning: SFTPGo has also built-in 2FA support.
File: examples/ldapauthserver/README.md
LDAPAuthServer
This is an example for an HTTP server to use as external authentication HTTP hook. It performs authentication against an LDAP server.
It is tested against 389ds and can be used as starting point to authenticate using any LDAP server including Active Directory.
You can configure the server using the ldapauth.toml configuration file.
You can build this example using the following command:
go build -ldflags "-s -w" -o ldapauthserver:warning: A plugin for LDAP/Active Directory authentication is also available.
File: examples/ldapauth/README.md
LDAPAuth
This is an example for an external authentication program. It performs authentication against an LDAP server.
It is tested against 389ds and can be used as starting point to authenticate using any LDAP server including Active Directory.
You need to change the LDAP connection parameters and the user search query to match your environment.
You can build this example using the following command:
go build -ldflags "-s -w" -o ldapauthThis program assumes that the 389ds schema was extended to add support for public keys using the following ldif file placed in /etc/dirsrv/schema/98openssh-ldap.ldif:
dn: cn=schema
changetype: modify
add: attributetypes
attributetypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DESC 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
-
add: objectclasses
objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY DESC 'MANDATORY: OpenSSH LPK objectclass' MUST ( uid ) MAY ( sshPublicKey ) )
-
dn: cn=sshpublickey,cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config
changetype: add
cn: sshpublickey
nsIndexType: eq
nsIndexType: pres
nsSystemIndex: false
objectClass: top
objectClass: nsIndex
dn: cn=sshpublickey_self_manage,ou=groups,dc=example,dc=com
changetype: add
objectClass: top
objectClass: groupofuniquenames
cn: sshpublickey_self_manage
dn: dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr = "sshPublicKey") (version 3.0; acl "Allow members of sshpublickey_self_manage to edit their keys"; allow(write) (groupdn = "ldap:///cn=sshpublickey_self_manage,ou=groups,dc=example,dc=com" and userdn="ldap:///self" ); )
-:warning: A plugin for LDAP/Active Directory authentication is also available.