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.

Note: 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 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:

  • ChrootDirectory
  • ForceCommand
  • 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_config before 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

Let's connect

Interested in discussing software architecture, engineering challenges or potential collaboration? Feel free to get in touch.

© 2026 Rajdip Khavad. All rights reserved.