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

Boost your Azure Cosmos DB Efficiency with Azure Advisor Insights

Azure Cosmos DB is Microsoft’s globally distributed, multi-model database service, trusted for mission-critical workloads that demand high ava...

1 day ago

Microsoft Azure Fundamentals #5: Complex Error Handling Patterns for High-Volume Microsoft Dataverse Integrations in Azure

🚀 1. Problem Context When integrating Microsoft Dataverse with Azure services (e.g., Azure Service Bus, Azure Functions, Logic Apps, Azure SQ...

1 day ago

Using the Secret Management PowerShell Module with Azure Key Vault and Azure Automation

Automation account credential resources are the easiest way to manage credentials for Azure Automation runbooks. The Secret Management module ...

2 days ago

Microsoft Azure Fundamentals #4: Azure Service Bus Topics and Subscriptions for multi-system CRM workflows in Microsoft Dataverse / Dynamics 365

🚀 1. Scenario Overview In modern enterprise environments, a single business event in Microsoft Dataverse (CRM) can trigger workflows across m...

2 days ago

Easily connect AI workloads to Azure Blob Storage with adlfs

Microsoft works with the fsspec open-source community to enhance adlfs. This update delivers faster file operations and improved reliability f...

3 days ago

Microsoft Azure Fundamentals #3: Maximizing Event-Driven Architecture in Microsoft Power Platform

🧩 1. Overview Event-driven architecture (EDA) transforms how systems communicate.Instead of traditional request–response or batch integration...

3 days ago

Azure Developer CLI (azd) – October 2025

This post announces the October release of the Azure Developer CLI (`azd`). The post Azure Developer CLI (azd) – October 2025 appeared f...

3 days ago

Microsoft Azure Fundamentals #2: Designing Real-Time Bi-Directional Sync Between Dataverse and Azure SQL for Multi-Region Deployments

Here’s a detailed technical breakdown of designing a real-time bi-directional sync between Dataverse and Azure SQL for multi-region deployment...

4 days ago

Azure DevOps local MCP Server is generally available

Today we are excited to take our local MCP Server for Azure DevOps out of preview 🥳. Since the initial preview announcement, we’ve work...

5 days ago

Announcing the new Azure DevOps Server RC Release

We’re excited to announce the release candidate (RC) of Azure DevOps Server, bringing new features previously available in our hosted version....

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