How to Set Up FTP Server with IIS on Windows Server 2025

Despite the widespread adoption of SFTP and HTTPS-based file transfer, FTP remains a common requirement for legacy application integrations, hosting customers, and automated data pipelines. IIS on Windows Server 2025 includes a full-featured FTP service with support for explicit and implicit FTPS, multiple user isolation modes, passive mode port ranges, and integration with Windows authentication and NTFS permissions. This tutorial covers installing the FTP service, creating an FTP site, configuring FTPS, setting up user isolation, managing Windows Firewall for passive mode, and testing with common FTP clients.

Prerequisites

  • Windows Server 2025 with the Web Server (IIS) role installed, or a clean server where you will install both
  • Administrator privileges on the server
  • An SSL certificate in the Local Machine certificate store (for FTPS)
  • A Windows user account or Active Directory account for authenticated FTP access
  • Firewall access on TCP 21 (FTP command channel) and your chosen passive port range
  • Sufficient disk space on the directory you will designate as the FTP root

Step 1: Install the FTP Server Feature

Install the FTP Server role service with its management tools in an elevated PowerShell session:

# Install FTP Server and IIS management console
Install-WindowsFeature -Name Web-Ftp-Server -IncludeManagementTools

# If IIS (Web-Server) is not yet installed, install both together
Install-WindowsFeature -Name Web-Server, Web-Ftp-Server -IncludeManagementTools

# Verify the FTP service is installed
Get-WindowsFeature -Name Web-Ftp-Server

# Check the FTP service status
Get-Service -Name ftpsvc

The ftpsvc service is the Microsoft FTP Service. Set it to start automatically and start it now:

Set-Service -Name ftpsvc -StartupType Automatic
Start-Service -Name ftpsvc

Step 2: Create the FTP Site

Create a physical directory for the FTP root, then create the FTP site using the New-WebFtpSite cmdlet or IIS Manager:

# Create the FTP root directory
New-Item -Path "D:FTPRoot" -ItemType Directory -Force

# Grant the NETWORK SERVICE account read access (needed by IIS/FTP)
icacls "D:FTPRoot" /grant "NETWORK SERVICE:(RX)" /T

# Grant FTP users appropriate NTFS permissions
icacls "D:FTPRoot" /grant "CONTOSOFTPUsers:(M)" /T

# Create the FTP site on port 21
New-WebFtpSite `
    -Name "Contoso FTP" `
    -Port 21 `
    -PhysicalPath "D:FTPRoot"

# Verify the site was created
Get-Website -Name "Contoso FTP"

After creation, the FTP site binds to all IP addresses on port 21 by default. To restrict it to a specific IP address:

# Update FTP binding to a specific IP
Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/bindings/binding[@protocol='ftp']" `
    -PSPath "IIS:" `
    -Name bindingInformation `
    -Value "192.168.1.10:21:"

Step 3: Configure FTPS (FTP over SSL)

Plain FTP transmits credentials and data in cleartext. FTPS encrypts the command and data channels using TLS. IIS supports both explicit FTPS (STARTTLS on port 21) and implicit FTPS (TLS-always on port 990).

# Get the thumbprint of your SSL certificate
Get-ChildItem -Path Cert:LocalMachineMy | Where-Object { $_.Subject -like "*ftp.contoso.com*" } |
    Select-Object Subject, Thumbprint

$CertThumb = "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2"

# Configure explicit FTPS (TLS optional — clients can negotiate TLS via AUTH TLS command)
Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/ftpServer/security/ssl" `
    -PSPath "IIS:" `
    -Name serverCertHash `
    -Value $CertThumb

# Set SSL policy: SslAllow = optional, SslRequire = mandatory, SslRequireCredentials = require TLS before login
Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/ftpServer/security/ssl" `
    -PSPath "IIS:" `
    -Name controlChannelPolicy `
    -Value "SslRequire"

Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/ftpServer/security/ssl" `
    -PSPath "IIS:" `
    -Name dataChannelPolicy `
    -Value "SslRequire"

# For implicit FTPS (port 990), add a second binding
New-WebFtpSite `
    -Name "Contoso FTP Implicit" `
    -Port 990 `
    -PhysicalPath "D:FTPRoot"

Step 4: Configure Authentication and Authorization

Enable the appropriate authentication method and set authorization rules controlling what authenticated users can do:

# Disable Anonymous Authentication for the FTP site
Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/ftpServer/security/authentication/anonymousAuthentication" `
    -PSPath "IIS:" `
    -Name enabled `
    -Value $false

# Enable Basic Authentication (works with Windows accounts)
Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/ftpServer/security/authentication/basicAuthentication" `
    -PSPath "IIS:" `
    -Name enabled `
    -Value $true

# Add an FTP authorization rule — allow all users Read and Write access
Add-WebConfiguration `
    -Filter "system.ftpServer/security/authorization" `
    -PSPath "IIS:SitesContoso FTP" `
    -Value @{
        accessType = "Allow"
        users      = "*"
        roles      = ""
        permissions = "Read, Write"
    }

Step 5: Configure FTP User Isolation

User isolation prevents FTP users from navigating above their home directory, which is critical for shared hosting and multi-tenant FTP scenarios. IIS supports three isolation modes:

  • No isolation — All users see the FTP root. Not recommended for shared hosting.
  • User name directory — Each user is confined to a subdirectory matching their username (D:FTPRootLocalUserusername for local accounts).
  • Start in user name directory — Users start in their named directory but can navigate up. A middle-ground option.
# Enable user name directory isolation (users cannot navigate above their home dir)
Set-WebConfigurationProperty `
    -Filter "system.applicationHost/sites/site[@name='Contoso FTP']/ftpServer/userIsolation" `
    -PSPath "IIS:" `
    -Name mode `
    -Value "IsolateRootDirectoryOnly"

# Create per-user directories following the required naming convention
# For local Windows accounts: D:FTPRootLocalUser
New-Item -Path "D:FTPRootLocalUserjsmith" -ItemType Directory -Force
icacls "D:FTPRootLocalUserjsmith" /grant "jsmith:(M)" /T

New-Item -Path "D:FTPRootLocalUserbthompson" -ItemType Directory -Force
icacls "D:FTPRootLocalUserbthompson" /grant "bthompson:(M)" /T

Step 6: Configure Windows Firewall for Passive FTP

Passive FTP requires the client to connect to a server-chosen data port in a high-port range. By default, the FTP service uses ephemeral ports, which makes firewall configuration difficult. Define a fixed passive port range:

# Set a fixed passive port range in IIS (e.g., 49152 to 49252)
Set-WebConfigurationProperty `
    -Filter "system.ftpServer/firewallSupport" `
    -PSPath "IIS:" `
    -Name lowDataChannelPort `
    -Value 49152

Set-WebConfigurationProperty `
    -Filter "system.ftpServer/firewallSupport" `
    -PSPath "IIS:" `
    -Name highDataChannelPort `
    -Value 49252

# Specify the external IP address of the server (for NAT environments)
Set-WebConfigurationProperty `
    -Filter "system.ftpServer/firewallSupport" `
    -PSPath "IIS:" `
    -Name externalIp4Address `
    -Value "203.0.113.25"

# Restart the FTP service to apply port range settings
Restart-Service -Name ftpsvc

# Open Windows Firewall rules for FTP
New-NetFirewallRule `
    -Name "FTP-Inbound-Control" `
    -DisplayName "FTP Server Control (TCP 21)" `
    -Protocol TCP -LocalPort 21 `
    -Direction Inbound -Action Allow

New-NetFirewallRule `
    -Name "FTP-Inbound-Passive" `
    -DisplayName "FTP Server Passive Data (TCP 49152-49252)" `
    -Protocol TCP -LocalPort 49152-49252 `
    -Direction Inbound -Action Allow

New-NetFirewallRule `
    -Name "FTPS-Inbound-Implicit" `
    -DisplayName "FTPS Implicit (TCP 990)" `
    -Protocol TCP -LocalPort 990 `
    -Direction Inbound -Action Allow

Step 7: Test with FTP Clients

Test anonymous connectivity with the built-in FTP command-line tool, and authenticated/FTPS connections with WinSCP or FileZilla:

# Test basic FTP connection from the server itself
ftp -v 127.0.0.1

# Test FTPS using curl (supports explicit FTPS with --ftp-ssl)
curl -v --ftp-ssl `
     --user "jsmith:P@ssw0rd!" `
     ftp://ftp.contoso.com/ `
     --cacert "D:Certscontoso-ca.crt"

# Upload a file via FTPS with curl
curl -v --ftp-ssl `
     --user "jsmith:P@ssw0rd!" `
     -T "C:LocalFilesreport.csv" `
     ftp://ftp.contoso.com/report.csv `
     --cacert "D:Certscontoso-ca.crt"

# Check ftpsvc service status and recent event log entries
Get-EventLog -LogName System -Source "Microsoft-Windows-FTPSVC" -Newest 20 |
    Format-Table TimeGenerated, EntryType, Message -AutoSize

In WinSCP, select FTPS as the protocol, enter your server hostname, port 21 (explicit) or 990 (implicit), and your Windows credentials. FileZilla uses the same settings — select FTP over TLS (explicit) or FTP over TLS (implicit) from the encryption dropdown.

Running a secure, well-isolated FTP service on Windows Server 2025 requires attention to authentication, SSL configuration, NTFS permissions, and firewall port management — but IIS provides all the tools to accomplish this without third-party software. With FTPS enforcing TLS for both the command and data channels, user isolation preventing cross-account access, and a defined passive port range simplifying firewall rules, the resulting FTP setup is both functional and production-hardened. For greenfield deployments, consider pairing the IIS FTP service with SFTP via OpenSSH (also included in Windows Server 2025) to cover both legacy FTP clients and modern secure transfer requirements.