How to Set Up Windows Server 2016 FTP Server

FTP (File Transfer Protocol) allows clients to upload and download files to and from a server. IIS 10.0 on Windows Server 2016 includes a full-featured FTP server. This guide covers installing the IIS FTP service, creating an FTP site, configuring authentication and authorization, enabling passive mode with firewall rules, setting up SSL (FTPS), and managing FTP user isolation.

Step 1: Install IIS and the FTP Server Feature

# Install IIS Web Server and FTP Server features
Install-WindowsFeature -Name Web-Server, Web-Ftp-Server, Web-Ftp-Service, Web-Ftp-Extensibility -IncludeManagementTools

# Verify installation
Get-WindowsFeature -Name Web-Ftp-Server, Web-Ftp-Service | Select-Object Name, InstallState

# Verify the FTP service is available
Get-Service ftpsvc | Select-Object Status, StartType

Step 2: Create the FTP Root Directory

# Create the FTP root directory on a data drive
New-Item -ItemType Directory -Path "D:FTPRoot" -Force
New-Item -ItemType Directory -Path "D:FTPRootuploads" -Force

# Create per-user directories for user isolation
New-Item -ItemType Directory -Path "D:FTPRootLocalUserftpuser1" -Force
New-Item -ItemType Directory -Path "D:FTPRootLocalUserftpuser2" -Force

# Create a test file
Set-Content -Path "D:FTPRootwelcome.txt" -Value "Welcome to the FTP Server."

Step 3: Create a Local FTP User Account

# Create a local user account for FTP access
$ftpPassword = ConvertTo-SecureString "FtpP@ss2016!" -AsPlainText -Force
New-LocalUser -Name "ftpuser1" -Password $ftpPassword -Description "FTP User 1" -PasswordNeverExpires $true

# Optionally, deny interactive logon (FTP only)
# This is done via Local Security Policy or group membership - do not add to Remote Desktop Users

Step 4: Create the FTP Site

# Import WebAdministration module
Import-Module WebAdministration

# Create a new FTP site bound to port 21 on all IP addresses
New-WebFtpSite -Name "MyFTPSite" -Port 21 -PhysicalPath "D:FTPRoot"

# Start the FTP site
Start-WebItem -PSPath "IIS:SitesMyFTPSite"

# Verify the site was created and is running
Get-WebSite -Name "MyFTPSite" | Select-Object Name, State, PhysicalPath

Step 5: Configure FTP Authentication

Enable basic authentication so clients can log in with a username and password. Anonymous authentication should be disabled on secure FTP sites:

# Disable anonymous authentication
Set-WebConfigurationProperty -Filter /system.ftpServer/security/authentication/anonymousAuthentication `
    -PSPath "IIS:SitesMyFTPSite" -Name enabled -Value False

# Enable basic authentication
Set-WebConfigurationProperty -Filter /system.ftpServer/security/authentication/basicAuthentication `
    -PSPath "IIS:SitesMyFTPSite" -Name enabled -Value True

# Verify authentication settings
Get-WebConfiguration -Filter /system.ftpServer/security/authentication/* -PSPath "IIS:SitesMyFTPSite"

Step 6: Configure FTP Authorization Rules

Authorization rules define which users can read and/or write to the FTP site:

# Add a read/write authorization rule for a specific user
Add-WebConfiguration -Filter /system.ftpServer/security/authorization `
    -PSPath "IIS:SitesMyFTPSite" `
    -Value @{accessType="Allow"; users="ftpuser1"; permissions="Read,Write"}

# Add a read-only rule for another user
Add-WebConfiguration -Filter /system.ftpServer/security/authorization `
    -PSPath "IIS:SitesMyFTPSite" `
    -Value @{accessType="Allow"; users="ftpuser2"; permissions="Read"}

# Deny all other users
Add-WebConfiguration -Filter /system.ftpServer/security/authorization `
    -PSPath "IIS:SitesMyFTPSite" `
    -Value @{accessType="Deny"; users="*"; permissions="Read,Write"}

Step 7: Configure FTP User Isolation

User isolation confines each FTP user to their own home directory, preventing users from browsing other users’ folders:

# Enable user isolation - isolate users to their home directory under LocalUser
Set-WebConfiguration -Filter system.ftpServer/userIsolation `
    -PSPath "IIS:SitesMyFTPSite" `
    -Value @{mode="IsolateAllDirectories"}

# The directory structure must be: LocalUser
# Already created in Step 2 above

Step 8: Enable FTPS (FTP over SSL)

FTPS encrypts the FTP control and data channels using SSL/TLS, protecting credentials and data in transit:

# Create a self-signed certificate for FTP (or use an existing one)
$cert = New-SelfSignedCertificate `
    -DnsName "ftp.example.com" `
    -CertStoreLocation "cert:LocalMachineMy" `
    -NotAfter (Get-Date).AddYears(2)

$thumbprint = $cert.Thumbprint

# Bind the SSL certificate to the FTP site
Set-WebConfiguration -Filter /system.ftpServer/security/ssl `
    -PSPath "IIS:SitesMyFTPSite" `
    -Value @{
        serverCertHash = $thumbprint
        serverCertStoreName = "My"
        ssl128 = $false
        controlChannelPolicy = "SslRequire"
        dataChannelPolicy = "SslRequire"
    }

Step 9: Configure Passive Mode and Firewall Rules

FTP passive mode requires a range of ports for data connections. Configure the data channel port range and open those ports in the firewall:

# Set the passive port range for FTP data connections (49152-65535 is common)
Set-WebConfiguration -Filter /system.ftpServer/firewallSupport `
    -PSPath "IIS:" `
    -Value @{
        lowDataChannelPort = 49152
        highDataChannelPort = 65535
    }

# Open the FTP command port (21) in Windows Firewall
New-NetFirewallRule -DisplayName "FTP Server Port 21" -Direction Inbound `
    -Protocol TCP -LocalPort 21 -Action Allow -Profile Domain,Private,Public

# Open the passive data port range
New-NetFirewallRule -DisplayName "FTP Passive Ports 49152-65535" -Direction Inbound `
    -Protocol TCP -LocalPort 49152-65535 -Action Allow -Profile Domain,Private,Public

# Enable the FTP stateful firewall helper (for active FTP through NAT)
netsh advfirewall set global statefulftp enable

Step 10: Test and Verify the FTP Server

# Verify the FTP service is running
Get-Service ftpsvc

# Test FTP connection using the built-in FTP client (from command prompt)
# (Replace with your server IP and credentials)
ftp 192.168.1.10

# Test from PowerShell using System.Net.FtpWebRequest
$ftpRequest = [System.Net.FtpWebRequest]::Create("ftp://192.168.1.10/")
$ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectory
$ftpRequest.Credentials = New-Object System.Net.NetworkCredential("ftpuser1","FtpP@ss2016!")
$response = $ftpRequest.GetResponse()
Write-Host "FTP Response: $($response.StatusDescription)"
$response.Close()

# Check IIS FTP logs
Get-Content "C:inetpublogsLogFilesFTPSVC**.log" -Tail 30 -ErrorAction SilentlyContinue

The FTP Server is now configured on Windows Server 2016 with authentication, authorization rules, user isolation, FTPS encryption, and proper firewall configuration. FTPS ensures that credentials and file transfers are encrypted, making it suitable for transferring sensitive files. For internet-facing FTP services, consider using SFTP via an SSH server as a more modern and secure alternative to traditional FTP.