Loading...

Enable SFTP on Azure File Share using ARM Template and upload files using WinScp

Enable SFTP on Azure File Share using ARM Template and upload files using WinScp

SFTP is a very widely used protocol which many organizations use today for transferring files within their organization or across organizations. Creating a VM based SFTP is costly and high-maintenance. ACI service is very inexpensive and requires very little maintenance, while data is stored in Azure Files which is a fully managed SMB service in cloud.

This template demonstrates an creating a SFTP server using Azure Container Instances (ACI). The template generates two resources:

  1. storage account is the storage account used for persisting data, and contains the Azure Files share
  2. sftp-group is a container group with a mounted Azure File Share. The Azure File Share will provide persistent storage after the container is terminated.

 

ARM Template for creation of SFTP with New Azure File Share and a new Azure Storage account

Resources.json

{

  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",

  "contentVersion": "1.0.0.0",

  "metadata": {

    "_generator": {

      "name": "bicep",

      "version": "0.4.63.48766",

      "templateHash": "17013458610905703770"

    }

  },

  "parameters": {

    "storageAccountType": {

      "type": "string",

      "defaultValue": "Standard_LRS",

      "metadata": {

        "description": "Storage account type"

      },

      "allowedValues": [

        "Standard_LRS",

        "Standard_ZRS",

        "Standard_GRS"

      ]

    },

    "storageAccountPrefix": {

      "type": "string",

      "defaultValue": "sftpstg",

      "metadata": {

        "description": "Prefix for new storage account"

      }

    },

    "fileShareName": {

      "type": "string",

      "defaultValue": "sftpfileshare",

      "metadata": {

        "description": "Name of file share to be created"

      }

    },

    "sftpUser": {

      "type": "string",

      "defaultValue": "sftp",

      "metadata": {

        "description": "Username to use for SFTP access"

      }

    },

    "sftpPassword": {

      "type": "securestring",

      "metadata": {

        "description": "Password to use for SFTP access"

      }

    },

    "location": {

      "type": "string",

      "defaultValue": "[resourceGroup().location]",

      "metadata": {

        "description": "Primary location for resources"

      }

    },

    "containerGroupDNSLabel": {

      "type": "string",

      "defaultValue": "[uniqueString(resourceGroup().id, deployment().name)]",

      "metadata": {

        "description": "DNS label for container group"

      }

    }

  },

  "functions": [],

  "variables": {

    "sftpContainerName": "sftp",

    "sftpContainerGroupName": "sftp-group",

    "sftpContainerImage": "atmoz/sftp:debian",

    "sftpEnvVariable": "[format('{0}:{1}:1001', parameters('sftpUser'), parameters('sftpPassword'))]",

    "storageAccountName": "[take(toLower(format('{0}{1}', parameters('storageAccountPrefix'), uniqueString(resourceGroup().id))), 24)]"

  },

  "resources": [

    {

      "type": "Microsoft.Storage/storageAccounts",

      "apiVersion": "2019-06-01",

      "name": "[variables('storageAccountName')]",

      "location": "[parameters('location')]",

      "kind": "StorageV2",

      "sku": {

        "name": "[parameters('storageAccountType')]"

      }

    },

    {

      "type": "Microsoft.Storage/storageAccounts/fileServices/shares",

      "apiVersion": "2019-06-01",

      "name": "[toLower(format('{0}/default/{1}', variables('storageAccountName'), parameters('fileShareName')))]",

      "dependsOn": [

        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"

      ]

    },

    {

      "type": "Microsoft.ContainerInstance/containerGroups",

      "apiVersion": "2019-12-01",

      "name": "[variables('sftpContainerGroupName')]",

      "location": "[parameters('location')]",

      "properties": {

        "containers": [

          {

            "name": "[variables('sftpContainerName')]",

            "properties": {

              "image": "[variables('sftpContainerImage')]",

              "environmentVariables": [

                {

                  "name": "SFTP_USERS",

                  "secureValue": "[variables('sftpEnvVariable')]"

                }

              ],

              "resources": {

                "requests": {

                  "cpu": 1,

                  "memoryInGB": 1

                }

              },

              "ports": [

                {

                  "port": 22,

                  "protocol": "TCP"

                }

              ],

              "volumeMounts": [

                {

                  "mountPath": "[format('/home/{0}/upload', parameters('sftpUser'))]",

                  "name": "sftpvolume",

                  "readOnly": false

                }

              ]

            }

          }

        ],

        "osType": "Linux",

        "ipAddress": {

          "type": "Public",

          "ports": [

            {

              "port": 22,

              "protocol": "TCP"

            }

          ],

          "dnsNameLabel": "[parameters('containerGroupDNSLabel')]"

        },

        "restartPolicy": "OnFailure",

        "volumes": [

          {

            "name": "sftpvolume",

            "azureFile": {

              "readOnly": false,

              "shareName": "[parameters('fileShareName')]",

              "storageAccountName": "[variables('storageAccountName')]",

              "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2019-06-01').keys[0].value]"

            }

          }

        ]

      },

      "dependsOn": [

        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"

      ]

    }

  ],

  "outputs": {

    "containerDNSLabel": {

      "type": "string",

      "value": "[format('{0}.{1}.azurecontainer.io', reference(resourceId('Microsoft.ContainerInstance/containerGroups', variables('sftpContainerGroupName'))).ipAddress.dnsNameLabel, reference(resourceId('Microsoft.ContainerInstance/containerGroups', variables('sftpContainerGroupName')), '2019-12-01', 'full').location)]"

    }

  }

}

 

Parameters.json

{

  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",

  "contentVersion": "1.0.0.0",

  "parameters": {

    "storageAccountType": {

      "value": "Standard_LRS"

    },

    "storageAccountPrefix": {

      "value": "sftpstg"

    },

    "fileShareName": {

      "value": "sftpfileshare"

    },

    "sftpUser": {

      "value": "sftp"

    },

    "sftpPassword": {

      "value": null

    },

    "location": {

      "value": "[resourceGroup().location]"

    },

    "containerGroupDNSLabel": {

      "value": "[uniqueString(resourceGroup().id, deployment().name)]"

    }

  }

}

 

 

ARM Template to Enable SFTP for an Existing Azure File Share in Azure Storage account

Resources.json

{

  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",

  "contentVersion": "1.0.0.0",

  "metadata": {

    "_generator": {

      "name": "bicep",

      "version": "0.4.63.48766",

      "templateHash": "16190402726175806996"

    }

  },

  "parameters": {

    "existingStorageAccountResourceGroupName": {

      "type": "string",

      "metadata": {

        "description": "Resource group for existing storage account"

      }

    },

    "existingStorageAccountName": {

      "type": "string",

      "metadata": {

        "description": "Name of existing storage account"

      }

    },

    "existingFileShareName": {

      "type": "string",

      "metadata": {

        "description": "Name of existing file share to be mounted"

      }

    },

    "sftpUser": {

      "type": "string",

      "defaultValue": "sftp",

      "metadata": {

        "description": "Username to use for SFTP access"

      }

    },

    "sftpPassword": {

      "type": "securestring",

      "metadata": {

        "description": "Password to use for SFTP access"

      }

    },

    "location": {

      "type": "string",

      "defaultValue": "[resourceGroup().location]",

      "metadata": {

        "description": "Primary location for resources"

      }

    },

    "containerGroupDNSLabel": {

      "type": "string",

      "defaultValue": "[uniqueString(resourceGroup().id, deployment().name)]",

      "metadata": {

        "description": "DNS label for container group"

      }

    }

  },

  "functions": [],

  "variables": {

    "sftpContainerName": "sftp",

    "sftpContainerGroupName": "sftp-group",

    "sftpContainerImage": "atmoz/sftp:debian",

    "sftpEnvVariable": "[format('{0}:{1}:1001', parameters('sftpUser'), parameters('sftpPassword'))]"

  },

  "resources": [

    {

      "type": "Microsoft.ContainerInstance/containerGroups",

      "apiVersion": "2019-12-01",

      "name": "[variables('sftpContainerGroupName')]",

      "location": "[parameters('location')]",

      "properties": {

        "containers": [

          {

            "name": "[variables('sftpContainerName')]",

            "properties": {

              "image": "[variables('sftpContainerImage')]",

              "environmentVariables": [

                {

                  "name": "SFTP_USERS",

                  "secureValue": "[variables('sftpEnvVariable')]"

                }

              ],

              "resources": {

                "requests": {

                  "cpu": 1,

                  "memoryInGB": 1

                }

              },

              "ports": [

                {

                  "port": 22,

                  "protocol": "TCP"

                }

              ],

              "volumeMounts": [

                {

                  "mountPath": "[format('/home/{0}/upload', parameters('sftpUser'))]",

                  "name": "sftpvolume",

                  "readOnly": false

                }

              ]

            }

          }

        ],

        "osType": "Linux",

        "ipAddress": {

          "type": "Public",

          "ports": [

            {

              "port": 22,

              "protocol": "TCP"

            }

          ],

          "dnsNameLabel": "[parameters('containerGroupDNSLabel')]"

        },

        "restartPolicy": "OnFailure",

        "volumes": [

          {

            "name": "sftpvolume",

            "azureFile": {

              "readOnly": false,

              "shareName": "[parameters('existingFileShareName')]",

              "storageAccountName": "[parameters('existingStorageAccountName')]",

              "storageAccountKey": "[listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('existingStorageAccountResourceGroupName')), 'Microsoft.Storage/storageAccounts', parameters('existingStorageAccountName')), '2019-06-01').keys[0].value]"

            }

          }

        ]

      }

    }

  ],

  "outputs": {

    "containerDNSLabel": {

      "type": "string",

      "value": "[format('{0}.{1}.azurecontainer.io', reference(resourceId('Microsoft.ContainerInstance/containerGroups', variables('sftpContainerGroupName'))).ipAddress.dnsNameLabel, reference(resourceId('Microsoft.ContainerInstance/containerGroups', variables('sftpContainerGroupName')), '2019-12-01', 'full').location)]"

    }

  }

}

 

Parameters.json

{

  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",

  "contentVersion": "1.0.0.0",

  "parameters": {

    "existingStorageAccountResourceGroupName": {

      "value": null

    },

    "existingStorageAccountName": {

      "value": null

    },

    "existingFileShareName": {

      "value": null

    },

    "sftpUser": {

      "value": "sftp"

    },

    "sftpPassword": {

      "value": null

    },

    "location": {

      "value": "[resourceGroup().location]"

    },

    "containerGroupDNSLabel": {

      "value": "[uniqueString(resourceGroup().id, deployment().name)]"

    }

  }

}

 

Deploy the ARM Templates using PowerShell or Azure CLI or Custom Template deployment using Azure Portal.

  1. Choose the subscription you want to create the sftp service in
  2. Create a new Resource Group
  3. It will automatically create a storage account
  4. Give a File Share Name
  5. Provide a SFTP user name
  6. Provide a SFTP password
  7. Wait till the deployment is done successfully
  8. Click on the container sftp-group
  9. Copy the FQDN from the container group
  10. Download WinScp from WinSCP :: Official Site :: Download
  11. Provide Hostname : FQDN for ACI; Port Number: 22; User Name and Password
  12. Click on Login    

      Sudipta_Chakraborty_0-1666779055622.png

    13. Drag and drop a file from the left side to the Right side.    Sudipta_Chakraborty_1-1666779092579.png

   14. Now, go to the Storage Account and Navigate to File share. The file appears on the file share.

Sudipta_Chakraborty_2-1666779239538.png

 

Published on:

Learn more
Azure PaaS Blog articles
Azure PaaS Blog articles

Azure PaaS Blog articles

Share post:

Related posts

What’s new with Azure Repos?

We thought it was a good time to check in and highlight some of the work happening in Azure Repos. In this post, we’ve covered several recent ...

3 hours ago

Part 1: Building Your First Serverless HTTP API on Azure with Azure Functions & FastAPI

Introduction  This post is Part 1 of the series Serverless Application Development with Azure Functions and Azure Cosmos DB, where we explore ...

10 hours ago

Announcing GPT 5.2 Availability in Azure for U.S. Government Secret and Top Secret Clouds

Today, we are excited to announce that GPT-5.2, Azure OpenAI’s newest frontier reasoning model, is available in Microsoft Azure for U.S. Gover...

1 day ago

Sync data from Dynamics 365 Finance & Operations Azure SQL Database (Tier2) to local SQL Server (AxDB)

A new utility to synchronize data from D365FO cloud environments to local AxDB, featuring incremental sync and smart strategies.

1 day ago

Azure Cosmos DB Conf 2026 — Call for Proposals Is Now Open

Every production system has a story behind it. The scaling limit you didn’t expect. The data model that finally clicked. The tradeoff you had ...

1 day ago
Stay up to date with latest Microsoft Dynamics 365 and Power Platform news!
* Yes, I agree to the privacy policy