How to Set Up an SFTP Server on Windows with OpenSSH
Setting up an SFTP server on Windows can look straightforward until authentication works but the SFTP session fails, users land in the wrong directory, file permissions prevent uploads, or the OpenSSH service refuses to start after a configuration change.
I recently worked through this type of setup using Windows OpenSSH, including SFTP-only access, a restricted directory, NTFS permissions, sshd_config configuration, local connection testing, and troubleshooting an SFTP session that authenticated successfully but did not start correctly.
This guide focuses on the practical parts that matter when setting up a production-style SFTP server on Windows.
The examples use placeholder values such as sftp.example.com, sftpuser, and D:\SFTP. Replace them with values appropriate for your environment.
What Is SFTP?
SFTP stands for SSH File Transfer Protocol.
It provides secure file transfer over an SSH connection and is different from FTP over TLS (FTPS).
A typical SFTP connection looks like:
SFTP Client
|
| SSH / SFTP
| TCP 22
v
Windows Server
|
+-- OpenSSH Server (sshd)
|
+-- Authentication
|
+-- SFTP restrictions
|
+-- NTFS permissions
|
+-- SFTP directoryOn Windows, OpenSSH provides the SSH server functionality and SFTP capabilities.
Why Use OpenSSH Instead of FTP or FTPS?
If the requirement is specifically SFTP, the server needs an SSH/SFTP implementation.
SFTP is not simply FTP with encryption added.
The protocols are different:
| Protocol | Transport | Typical Port |
|---|---|---|
| FTP | FTP | 21 |
| FTPS | FTP + TLS | 21 / 990 |
| SFTP | SSH | 22 |
For a Windows server, Win32-OpenSSH is a natural option when SFTP is required and you want the service managed as part of Windows.
Environment Used for This Setup
The troubleshooting workflow behind this article used:
22sshd_configThe exact Windows Server/OpenSSH versions can vary, so always verify that the OpenSSH version installed on your server is supported for the Windows version you're running.
STEP 01Install OpenSSH Server
On supported Windows versions, OpenSSH Server can be installed as a Windows capability.
First check whether it is already installed.
From an elevated PowerShell session:
Get-WindowsCapability -Online |
Where-Object Name -like 'OpenSSH*'If OpenSSH Server is not installed, install it:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0Then verify the installation.
A typical location is:
C:\Windows\System32\OpenSSH\STEP 02Start the OpenSSH Server
Start the service:
Start-Service sshdConfigure it to start automatically:
Set-Service -Name sshd -StartupType AutomaticCheck the service:
Get-Service sshdYou should see the service in a running state.
If it does not start, don't immediately change multiple configuration settings.
First validate the configuration.
STEP 03Validate sshd_config Before Restarting
The OpenSSH server configuration is normally stored at:
C:\ProgramData\ssh\sshd_configBefore restarting the service after making changes, validate the configuration:
sshd -tIf the command returns an error, fix the configuration before restarting sshd.
This is one of the most useful troubleshooting steps when working with Windows OpenSSH.
STEP 04Create an SFTP User
Create a dedicated Windows user for SFTP instead of using an administrator account.
For example:
New-LocalUser `
-Name "sftpuser" `
-Password (Read-Host -AsSecureString "Password") `
-Description "SFTP user"The exact account-management approach can vary depending on whether your server uses local users or Active Directory.
The important principle is:
Give the SFTP account only the access it needs.
Avoid using a privileged Windows administrator account for routine file transfers.
STEP 05Create the SFTP Directory Structure
A simple structure can be:
D:\SFTP\
|
+-- sftpuser\
|
+-- upload\
|
+-- download\The directory layout should make the security boundary clear.
For example:
D:\SFTP
āāā sftpuser
āāā upload
āāā downloadThe user should have write access only where required.
STEP 06Configure NTFS Permissions
SFTP security is not controlled by sshd_config alone.
Windows NTFS permissions are equally important.
For example, the SFTP user may need write permission on:
D:\SFTP\sftpuser\uploadbut should not automatically receive unrestricted access to:
D:\or other server directories.
Use icacls to inspect and configure permissions.
For example:
icacls "D:\SFTP\sftpuser\upload"Be careful when modifying permissions recursively.
A useful rule is:
Chroot / SFTP root
ā
Restricted
ā
User-specific writable directorySTEP 07Configure SFTP-Only Access
If the user should only transfer files and should not receive an interactive SSH shell, configure an SFTP-only session.
A typical sshd_config pattern is:
Subsystem sftp sftp-server.exe
Match User sftpuser
ChrootDirectory D:/SFTP/sftpuser
ForceCommand internal-sftpThe important directives are:
`ChrootDirectory`
This restricts the user's SFTP view to the specified directory tree.
`ForceCommand internal-sftp`
This forces the account into the SFTP subsystem instead of allowing an interactive shell.
Important: Chroot Permissions
One of the easiest mistakes is giving the SFTP user write permission directly to the chroot root.
A safer structure is:
D:\SFTP\sftpuser
|
+-- upload
|
+-- downloadThe chroot root itself should be controlled appropriately, while the user receives write access to the specific child directory where uploads are expected.
This distinction matters because the chroot directory is part of the security boundary.
STEP 08Restart OpenSSH After Configuration Changes
After modifying sshd_config:
sshd -tIf validation succeeds:
Restart-Service sshdThen verify:
Get-Service sshdDo not restart the service repeatedly while configuration errors remain unresolved.
Validate first.
STEP 09Open TCP Port 22
SFTP normally uses TCP port 22.
Check whether the server is listening:
Get-NetTCPConnection -LocalPort 22You can also test locally:
Test-NetConnection localhost -Port 22If the service is running but port 22 is not reachable, investigate:
Do not troubleshoot external networking until local connectivity works.
STEP 10Test SFTP Locally First
Before testing the public hostname, test the SFTP service from the server or another machine on the same network.
For example:
sftp sftpuser@localhostor:
sftp sftpuser@server-hostnameIf the server accepts the connection locally, you have already eliminated several possible causes:
Internet
Cloud Firewall
External Network
DNSYou can then focus on the server configuration and permissions.
STEP 11Test From a Remote Windows PC
Once local testing works, test from the client machine:
sftp sftpuser@sftp.example.comIf the server uses a non-standard port:
sftp -P 2222 sftpuser@sftp.example.comFor the standard SFTP configuration:
Host: sftp.example.com
Port: 22
Username: sftpuser
Password: ********The same credentials can then be used from an SFTP client such as WinSCP or another compatible client.
# Troubleshooting Common Problems
Problem 1: Authentication Works but SFTP Session Fails
If authentication succeeds but the SFTP session immediately disconnects or fails to initialize, investigate what happens after authentication:
ChrootDirectoryForceCommandProblem 2: User Is Authenticated but Cannot Enter the SFTP Directory
Check:
ChrootDirectoryMake sure it points to a local directory rather than an unsuitable network/UNC path.
Then check permissions:
icacls "D:\SFTP\sftpuser"and:
icacls "D:\SFTP\sftpuser\upload"Problem 3: User Can Connect but Cannot Upload
Authentication and directory access are separate from write permission.
Check the writable directory:
icacls "D:\SFTP\sftpuser\upload"The user needs appropriate NTFS write permissions.
Do not solve an upload problem by giving the user full control over the entire drive.
Problem 4: OpenSSH Service Will Not Start
Run:
sshd -tThis should be the first check.
Then inspect Windows Event Viewer.
Also verify that the configuration contains a valid SFTP subsystem entry:
Subsystem sftp sftp-server.exeProblem 5: SFTP Connection Hangs
Check the problem from the bottom up:
Is sshd running?
ā
Does sshd -t pass?
ā
Is TCP 22 listening?
ā
Does localhost SFTP work?
ā
Does LAN SFTP work?
ā
Does external TCP 22 work?Problem 6: Need More Detailed SFTP Logs
For difficult issues, temporarily increase OpenSSH logging.
For example:
SyslogFacility LOCAL0
LogLevel DEBUG3Use high verbosity for troubleshooting rather than leaving unnecessarily verbose logging enabled permanently.
Problem 7: SSH Works but SFTP Is Not Restricted
Remember that:
SSH accessand:
SFTP-only accessare different configurations.
If the account should only transfer files, use an appropriate Match User / ForceCommand internal-sftp configuration and verify the actual behavior from a client.
# A Practical Production Configuration
A simplified configuration can look like:
Subsystem sftp sftp-server.exe
Match User sftpuser
ChrootDirectory D:/SFTP/sftpuser
ForceCommand internal-sftpDirectory:
D:\SFTP\sftpuser\
upload\
download\Conceptually:
sftpuser
|
+-- SFTP authentication
|
+-- chroot
|
+-- internal-sftp
|
+-- upload/download directories
|
+-- NTFS permissionsThe exact permissions and configuration should be adapted to the server's security requirements.
# Security Checklist
Before exposing the SFTP server externally:
sshd_config before restarting the servicePassword vs SSH Key Authentication
Password authentication is convenient, but SSH public-key authentication can provide stronger operational control for automated integrations.
A typical key-based flow is:
Client
|
+-- Private Key
|
v
SFTP Server
|
+-- Authorized Public Key
|
v
AuthenticationNever copy a private key onto the server.
The server only needs the corresponding public key.
For Windows OpenSSH, authorized-key storage and permissions depend on whether the account is an administrator or standard user.
# Why Local Testing Saved Time
One of the most useful lessons from troubleshooting an SFTP server is to avoid changing multiple variables simultaneously.
If:
sftp localhostfails, there is little value in troubleshooting DNS or an external firewall yet.
If:
sftp localhostworks but:
sftp sftp.example.comfails, the problem is more likely to be outside the local OpenSSH/SFTP configuration.
This simple separation can save significant troubleshooting time.
# Recommended Troubleshooting Checklist
When an SFTP deployment fails, work through this list:
[ ] OpenSSH Server installed
[ ] sshd service running
[ ] sshd -t succeeds
[ ] TCP 22 listening
[ ] Windows Firewall allows TCP 22
[ ] SFTP subsystem configured
[ ] User authentication works
[ ] Chroot directory exists
[ ] Chroot permissions are correct
[ ] Writable directory exists
[ ] NTFS permissions are correct
[ ] ForceCommand is correct
[ ] Local SFTP works
[ ] Remote SFTP works
[ ] Event Viewer checked
[ ] OpenSSH logs checked if requiredConclusion
A Windows SFTP server is not just an OpenSSH installation.
A reliable setup requires several layers to work together:
OpenSSH
+
sshd_config
+
Authentication
+
Chroot / SFTP restrictions
+
NTFS permissions
+
Windows Firewall
+
Network connectivityThe most important troubleshooting principle is to isolate these layers one at a time.
Start locally, validate sshd_config before restarting the service, verify authentication separately from filesystem permissions, and only move to external networking once the local SFTP workflow works.
That approach makes Windows SFTP deployments much easier to troubleshoot and maintain.
Official References
Need enterprise architecture consulting?
Explore our real-world case studies detailing production migrations, performance scaling, and high-throughput gateways.