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.
Note: The examples use placeholder values such as
sftp.example.com,sftpuser, andD: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 directory
On 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:
- Windows Server
- Win32-OpenSSH
- TCP port
22 - Windows local user authentication
sshd_config- SFTP-only access
- a restricted/chroot-style directory
- NTFS permissions
- local SFTP testing before external testing
The 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 1: Install 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.0
Then verify the installation.
A typical location is:
C:WindowsSystem32OpenSSH
Step 2: Start the OpenSSH Server
Start the service:
Start-Service sshd
Configure it to start automatically:
Set-Service -Name sshd -StartupType Automatic
Check the service:
Get-Service sshd
You 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 3: Validate sshd_config Before Restarting
The OpenSSH server configuration is normally stored at:
C:ProgramDatasshsshd_config
Before restarting the service after making changes, validate the configuration:
sshd -t
If 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 4: Create 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 5: Create 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
└── download
The user should have write access only where required.
Step 6: Configure 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:SFTPsftpuserupload
but should not automatically receive unrestricted access to:
D:
or other server directories.
Use icacls to inspect and configure permissions.
For example:
icacls "D:SFTPsftpuserupload"
Be careful when modifying permissions recursively.
A useful rule is:
Chroot / SFTP root
↓
Restricted
↓
User-specific writable directory
Step 7: Configure 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-sftp
The 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:SFTPsftpuser
|
+-- upload
|
+-- download
The 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 8: Restart OpenSSH After Configuration Changes
After modifying sshd_config:
sshd -t
If validation succeeds:
Restart-Service sshd
Then verify:
Get-Service sshd
Do not restart the service repeatedly while configuration errors remain unresolved.
Validate first.
Step 9: Open TCP Port 22
SFTP normally uses TCP port 22.
Check whether the server is listening:
Get-NetTCPConnection -LocalPort 22
You can also test locally:
Test-NetConnection localhost -Port 22
If the service is running but port 22 is not reachable, investigate:
- Windows Firewall
- cloud/security-group rules
- network ACLs
- load balancers
- NAT
- external firewall rules
Do not troubleshoot external networking until local connectivity works.
Step 10: Test 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@localhost
or:
sftp sftpuser@server-hostname
If the server accepts the connection locally, you have already eliminated several possible causes:
Internet
Cloud Firewall
External Network
DNS
You can then focus on the server configuration and permissions.
Step 11: Test From a Remote Windows PC
Once local testing works, test from the client machine:
sftp sftpuser@sftp.example.com
If the server uses a non-standard port:
sftp -P 2222 sftpuser@sftp.example.com
For 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.
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:
ChrootDirectoryForceCommand- NTFS permissions
- OpenSSH service configuration
- SFTP subsystem
- Windows Event Viewer
- OpenSSH logs
Problem 2: User Is Authenticated but Cannot Enter the SFTP Directory
Check:
ChrootDirectory
Make sure it points to a local directory rather than an unsuitable network/UNC path.
Then check permissions:
icacls "D:SFTPsftpuser"
and:
icacls "D:SFTPsftpuserupload"
Problem 3: User Can Connect but Cannot Upload
Authentication and directory access are separate from write permission.
Check the writable directory:
icacls "D:SFTPsftpuserupload"
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 -t
This 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.exe
Problem 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 DEBUG3
Use high verbosity for troubleshooting rather than leaving unnecessarily verbose logging enabled permanently.
Problem 7: SSH Works but SFTP Is Not Restricted
Remember that:
SSH access
and:
SFTP-only access
are 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 simplified configuration can look like:
Subsystem sftp sftp-server.exe
Match User sftpuser
ChrootDirectory D:/SFTP/sftpuser
ForceCommand internal-sftp
Directory:
D:SFTPsftpuser
upload
download
Conceptually:
sftpuser
|
+-- SFTP authentication
|
+-- chroot
|
+-- internal-sftp
|
+-- upload/download directories
|
+-- NTFS permissions
The exact permissions and configuration should be adapted to the server’s security requirements.
Security Checklist
- Use a dedicated SFTP account
- Avoid administrator accounts
- Restrict the account to the required directory
- Use SFTP-only access where appropriate
- Configure NTFS permissions carefully
- Use strong authentication
- Prefer SSH key authentication where appropriate
- Restrict inbound TCP 22 to known sources where possible
- Keep OpenSSH supported and updated
- Monitor authentication and SFTP logs
- Avoid exposing unnecessary services
- Test the account’s actual filesystem boundaries
- Validate
sshd_configbefore restarting the service
Password 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
Authentication
Never 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 localhost
fails, there is little value in troubleshooting DNS or an external firewall yet.
If:
sftp localhost
works but:
sftp sftp.example.com
fails, 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 required
Conclusion
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 connectivity
The 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
- Microsoft Learn — OpenSSH Server Configuration for Windows
- Microsoft Learn — Troubleshoot Common SFTP Issues Using OpenSSH
- OpenSSH documentation
