← Back to overview
November 19, 2012 · Endpoints FTP IIS8 Powershell Virtual Machines

Passive FTP and dynamic ports in IIS8 and Windows Azure Virtual Machines

Today Windows Azure supports up to 150 endpoints which is great for those applications that rely on persistent connections, like an FTP Server. You can run an FTP Server in 2 modes:

Passive mode is by far the most popular choice since it doesn't require you to open ports on your machine together with firewall exceptions and port forwarding. With passive mode it's up to the server to open the required ports. Let's see how we can get an FTP Server running in Passive mode on Windows Azure…

Configuring the endpoints

So I've created a new Windows Server 2012 VM in the portal. What we need to do now is open a range of ports (let's say 100) that can be used by the FTP Server for the data connection. Usually you would do this through the portal:

Adding 100 ports manually through the portal can take some time, that's why we'll do it with Powershell. Take a look at the following script:

# Arguments.
    [Microsoft.WindowsAzure.Management.ServiceManagement.Model.PersistentVMRoleContext]$vm = $(throw "'vm' is required."),
    [int]$publicPort = $(throw "'publicPort' is required."),
    [int]$dynamicPortFirst = $(throw "'dynamicPortFirst' is required."),
    [int]$dynamicPortLast = $(throw "'dynamicPortLast' is required.")
Get-ChildItem "${Env:ProgramFiles(x86)}\Microsoft SDKs\Windows Azure\PowerShell\Azure\*.dll" | ForEach-Object {[Reflection.Assembly]::LoadFile($_) | out-null }

$totalPorts = $dynamicPortLast - $dynamicPortFirst + 1
if ($totalPorts -gt 150)  
    $(throw "You cannot add more than 150 endpoints (this includes the Public FTP Port)")

# Add endpoints.
Write-Host -Fore Green "Adding: FTP-Public-$publicPort"  
Add-AzureEndpoint -VM $vm -Name "FTP-Public-$publicPort" -Protocol "tcp" -PublicPort $publicPort -LocalPort $publicPort  
for ($i = $dynamicPortFirst; $i -le $dynamicPortLast; $i++)  
    $name = "FTP-Dynamic-" + $i
    Write-Host -Fore Green "Adding: $name"
    Add-AzureEndpoint -VM $vm -Name $name -Protocol "tcp" -PublicPort $i -LocalPort $i

# Update VM.
Write-Host -Fore Green "Updating VM..."  
$vm | Update-AzureVM 
Write-Host -Fore Green "Done."  

This simple script does the required work for you:

Calling it is simple (here I'm opening port 2500 for the control connection and port range 10000-10125 for the data connection on my VM called passiveftp):

Import-AzurePublishSettingsFile 'C:\...'  
Select-AzureSubscription -SubscriptionName ...  
$vm = Get-AzureVM passiveftp
Add-AzureFtpEndpoints.ps1 $vm 2500 10000 10125  

And here is the result, all ports have been added:

Configuring the FTP Server

We made the required changes to the endpoints, the only thing we need to do now is configure the FTP Server. First we'll see how we can configure the server in the UI. The first thing we need to do is add a Web Role and choose to install the FTP Server role services:

Then we need to create a new FTP Site in IIS, configure the port (2500) and set the authentication:

In the portal we opened the tcp ports 10000 to 10125. If we want Passive FTP to work, we need to configure the same range in IIS. This is done in the FTP Firewall Support feature. You'll need to fill in exactly the same port range together with the public IP of the VM. To find it simply ping the VM (ping xxx.cloudapp.net) or go to the portal.

Finally open the firewall and open the control channel port (2500) and the data channel port range (10000-10125):

And there you go, I'm able to connect to my FTP Server using Passive mode:

Installing and configuring the FTP Server automatically

While it's great to click around like an IT Pro, it's always useful to have a script that does all the heavy lifting for you.

REM Variables.  
SETLOCAL EnableDelayedExpansion  
SET FtpSiteName=%1%  
SET FtpDirectory=%2%  
SET PublicPort=%3%  
SET DynamicPortFirst=%4%  
SET DynamicPortLast=%5%  
SET DynamicPortRange=%DynamicPortFirst%-%DynamicPortLast%  
SET PublicIP=%6%

REM Install FTP.  
start /w pkgmgr /iu:IIS-WebServerRole;IIS-FTPSvc;IIS-FTPServer;IIS-ManagementConsole

REM Create directory.  
IF NOT EXIST "%FtpDirectory%" (MKDIR "%FtpDirectory%")  
cacls "%FtpDirectory%" /G IUSR:W /T /E  
cacls "%FtpDirectory%" /G IUSR:R /T /E 

REM Configuring FTP site.  
pushd %windir%\system32\inetsrv  
appcmd add site /name:%FtpSiteName% /bindings:ftp://*:%PublicPort% /physicalpath:"%FtpDirectory%"  
appcmd set config -section:system.applicationHost/sites /[name='%FtpSiteName%'].ftpServer.security.ssl.controlChannelPolicy:"SslAllow"  
appcmd set config -section:system.applicationHost/sites /[name='%FtpSiteName%'].ftpServer.security.ssl.dataChannelPolicy:"SslAllow"  
appcmd set config -section:system.applicationHost/sites /[name='%FtpSiteName%'].ftpServer.security.authentication.basicAuthentication.enabled:true  
appcmd set config %FtpSiteName% /section:system.ftpserver/security/authorization /-[users='*'] /commit:apphost  
appcmd set config %FtpSiteName% /section:system.ftpserver/security/authorization /+[accessType='Allow',permissions='Read,Write',roles='',users='*'] /commit:apphost  
appcmd set config /section:system.ftpServer/firewallSupport /lowDataChannelPort:%DynamicPortFirst% /highDataChannelPort:%DynamicPortLast%  
appcmd set config -section:system.applicationHost/sites /siteDefaults.ftpServer.firewallSupport.externalIp4Address:"%PublicIP%" /commit:apphost

REM Configure firewall.  
netsh advfirewall firewall add rule name="FTP Public Port" dir=in action=allow protocol=TCP localport=%PublicPort%  
netsh advfirewall firewall add rule name="FTP Passive Dynamic Ports" dir=in action=allow protocol=TCP localport=%DynamicPortRange%

REM Restart the FTP service.  
net stop ftpsvc  
net start ftpsvc  

This script does… about everything:

Calling the script is very easy, you simply pass the name of the FTP Site, the root directory, the public port, the data channel range and the public IP. Remember that you need to run this on the VM, not on your own machine.

Install-FTPServer.cmd "passiveftp" "C:\FtpServer" 2500 10000 10125  

Both scripts are available on GitHub: https://github.com/sandrinodimattia/WindowsAzure-PassiveFTPinVM


  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket
Comments powered by Disqus