{"slug":"using-tailscale-on-azure-app-service","title":"Using Tailscale on Azure App Service","tags":["tailscale","setup"],"agent_summary":"Last validated: Jan 5, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Using Tailscale on Azure App Service\r\n\r\nLast validated: Jan 5, 2026\r\n\r\n[Azure App Service](https://azure.microsoft.com/en-us/products/app-service) is a popular cloud-hosting platform for running applications without managing servers yourself. However, it can be difficult to use Tailscale on Azure App Service, since it doesn't provide a `/dev/net/tun` device that Tailscale needs.\r\n\r\nYou can use Tailscale's [userspace networking mode](https://tailscale.com/docs/concepts/userspace-networking) to connect your apps to your Tailscale network.\r\n\r\n## [Step 1: Generate an auth key to authenticate your Azure App Service apps](https://tailscale.com/docs/install/cloud/azure/azure-app-service\\#step-1-generate-an-auth-key-to-authenticate-your-azure-app-service-apps)\r\n\r\nFirst, we'll generate an [auth key](https://tailscale.com/docs/features/access-control/auth-keys) to allow Azure to authenticate our app to join our network.\r\n\r\nOpen the [Keys](https://login.tailscale.com/admin/settings/keys) page of the admin console and select **Generate auth key**. We recommend using an [ephemeral key](https://tailscale.com/docs/features/ephemeral-nodes) for this purpose, since it will automatically clean up devices after they shut down.\r\n\r\n![Tailscale's auth key generation page](https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fephemeral-keys.de85b7fd.png&w=750&q=75)\r\n\r\nThe **Pre-approved** option will only display in the dialog if [device approval](https://tailscale.com/docs/features/access-control/device-management/device-approval) is enabled in your Tailscale network.\r\n\r\nNext, go to the [Azure Portal](https://portal.azure.com/) and then the **Configuration** page for your app. For **Config Var**, create a variable named `TAILSCALE_AUTHKEY`, with the `tskey-<key>` value you just created.\r\n\r\n![Azure App Service config var interface](https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fazure-config-vars.17fcfa0c.png&w=3840&q=75)\r\n\r\n## [Step 2: Configure your Dockerfile to install Tailscale](https://tailscale.com/docs/install/cloud/azure/azure-app-service\\#step-2-configure-your-dockerfile-to-install-tailscale)\r\n\r\nWe recommend using a [multistage Dockerfile](https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds) where the first stage builds your application, and the second stage pulls application code and Tailscale into the final image to be uploaded to Azure.\r\n\r\n1. Create an `sshd_config` file and add it to the Docker build directory. If this file does not exist before building the Dockerfile, the build will fail.\r\n\r\n2. Create a `start.sh` file at the root of your app. The Dockerfile specifies `/app/start.sh` as the initial process to run. This script needs to bring Tailscale up and then start the application binary. Use the `TAILSCALE_AUTHKEY` variable defined earlier when you bring Tailscale up.\r\n\r\nHere's a `start.sh` example file. Make sure to replace values needed for your build.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\n#!/bin/sh\r\n\r\n/usr/bin/ssh-keygen -A\r\nmkdir -p /var/run/sshd\r\n/usr/sbin/sshd\r\n\r\n/app/tailscaled --tun=userspace-networking --socks5-server=localhost:1055 &\r\n/app/tailscale up --auth-key=${TAILSCALE_AUTHKEY} --hostname=azure-app\r\necho Tailscale started\r\nALL_PROXY=socks5://localhost:1055/ /app/my-app\r\n```\r\n\r\n3. Create a `Dockerfile` at the root of your app and include the following details. Make sure to replace values needed for your build.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```dockerfile\r\nFROM golang:1-alpine3.21 AS builder\r\nWORKDIR /app\r\nCOPY . ./\r\n# This is where one could build the application code as well.\r\nFROM dotnetcore-docs-hello-world-linux.\r\n\r\nFROM alpine:latest\r\nRUN apk update && apk add ca-certificates bash sudo && rm -rf /var/cache/apk/*\r\n\r\n# Azure allows SSH access to the container. This isn't needed for Tailscale to\r\n# operate, but is really useful for debugging the application.\r\nRUN apk add openssh openssh-keygen && echo \"root:Docker!\" | chpasswd\r\nRUN apk add netcat-openbsd\r\nRUN mkdir -p /etc/ssh\r\nCOPY sshd_config /etc/ssh/\r\nEXPOSE 80 2222\r\n\r\n# Copy binary to production image.\r\nCOPY --from=builder /app/start.sh /app/start.sh\r\n# Change start.sh to be executable\r\nRUN chmod +x /app/start.sh\r\n\r\n# Copy Tailscale binaries from the tailscale image on Docker Hub.\r\nCOPY --from=docker.io/tailscale/tailscale:stable /usr/local/bin/tailscaled /app/tailscaled\r\nCOPY --from=docker.io/tailscale/tailscale:stable /usr/local/bin/tailscale /app/tailscale\r\nRUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale\r\n\r\n# Run on container startup.\r\nCMD [\"./app/start.sh\"]\r\n```\r\n\r\n\r\nThe next time your Azure app deploys, it will be able to connect to your private Tailscale network.\r\n\r\n## [Remove ephemeral nodes from a tailnet](https://tailscale.com/docs/install/cloud/azure/azure-app-service\\#remove-ephemeral-nodes-from-a-tailnet)\r\n\r\nWhen an ephemeral node goes offline, it is automatically removed from your tailnet. You can also control ephemeral node removal using the [`tailscale logout`](https://tailscale.com/docs/reference/tailscale-cli#logout) command to either manually force the removal or incorporate the command into the [`tailscaled`](https://tailscale.com/docs/reference/tailscaled) Tailscale daemon. For more information, refer to [Ephemeral nodes](https://tailscale.com/docs/features/ephemeral-nodes#faq).\r\n\r\n![Project Logo](https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed)\r\n\r\nAsk AI\r\n\r\nreCAPTCHA\r\n\r\nRecaptcha requires verification.\r\n\r\nprotected by **reCAPTCHA**\r\n","html":"<h1>Using Tailscale on Azure App Service</h1>\n<p>Last validated: Jan 5, 2026</p>\n<p><a href=\"https://azure.microsoft.com/en-us/products/app-service\">Azure App Service</a> is a popular cloud-hosting platform for running applications without managing servers yourself. However, it can be difficult to use Tailscale on Azure App Service, since it doesn't provide a <code>/dev/net/tun</code> device that Tailscale needs.</p>\n<p>You can use Tailscale's <a href=\"https://tailscale.com/docs/concepts/userspace-networking\">userspace networking mode</a> to connect your apps to your Tailscale network.</p>\n<h2><a href=\"https://tailscale.com/docs/install/cloud/azure/azure-app-service#step-1-generate-an-auth-key-to-authenticate-your-azure-app-service-apps\">Step 1: Generate an auth key to authenticate your Azure App Service apps</a></h2>\n<p>First, we'll generate an <a href=\"https://tailscale.com/docs/features/access-control/auth-keys\">auth key</a> to allow Azure to authenticate our app to join our network.</p>\n<p>Open the <a href=\"https://login.tailscale.com/admin/settings/keys\">Keys</a> page of the admin console and select <strong>Generate auth key</strong>. We recommend using an <a href=\"https://tailscale.com/docs/features/ephemeral-nodes\">ephemeral key</a> for this purpose, since it will automatically clean up devices after they shut down.</p>\n<p><img src=\"https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fephemeral-keys.de85b7fd.png&#x26;w=750&#x26;q=75\" alt=\"Tailscale&#x27;s auth key generation page\"></p>\n<p>The <strong>Pre-approved</strong> option will only display in the dialog if <a href=\"https://tailscale.com/docs/features/access-control/device-management/device-approval\">device approval</a> is enabled in your Tailscale network.</p>\n<p>Next, go to the <a href=\"https://portal.azure.com/\">Azure Portal</a> and then the <strong>Configuration</strong> page for your app. For <strong>Config Var</strong>, create a variable named <code>TAILSCALE_AUTHKEY</code>, with the <code>tskey-&#x3C;key></code> value you just created.</p>\n<p><img src=\"https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fazure-config-vars.17fcfa0c.png&#x26;w=3840&#x26;q=75\" alt=\"Azure App Service config var interface\"></p>\n<h2><a href=\"https://tailscale.com/docs/install/cloud/azure/azure-app-service#step-2-configure-your-dockerfile-to-install-tailscale\">Step 2: Configure your Dockerfile to install Tailscale</a></h2>\n<p>We recommend using a <a href=\"https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds\">multistage Dockerfile</a> where the first stage builds your application, and the second stage pulls application code and Tailscale into the final image to be uploaded to Azure.</p>\n<ol>\n<li>\n<p>Create an <code>sshd_config</code> file and add it to the Docker build directory. If this file does not exist before building the Dockerfile, the build will fail.</p>\n</li>\n<li>\n<p>Create a <code>start.sh</code> file at the root of your app. The Dockerfile specifies <code>/app/start.sh</code> as the initial process to run. This script needs to bring Tailscale up and then start the application binary. Use the <code>TAILSCALE_AUTHKEY</code> variable defined earlier when you bring Tailscale up.</p>\n</li>\n</ol>\n<p>Here's a <code>start.sh</code> example file. Make sure to replace values needed for your build.</p>\n<pre><code class=\"language-yaml\">#!/bin/sh\r\n\r\n/usr/bin/ssh-keygen -A\r\nmkdir -p /var/run/sshd\r\n/usr/sbin/sshd\r\n\r\n/app/tailscaled --tun=userspace-networking --socks5-server=localhost:1055 &#x26;\r\n/app/tailscale up --auth-key=${TAILSCALE_AUTHKEY} --hostname=azure-app\r\necho Tailscale started\r\nALL_PROXY=socks5://localhost:1055/ /app/my-app\n</code></pre>\n<ol start=\"3\">\n<li>Create a <code>Dockerfile</code> at the root of your app and include the following details. Make sure to replace values needed for your build.</li>\n</ol>\n<pre><code class=\"language-dockerfile\">FROM golang:1-alpine3.21 AS builder\r\nWORKDIR /app\r\nCOPY . ./\r\n# This is where one could build the application code as well.\r\nFROM dotnetcore-docs-hello-world-linux.\r\n\r\nFROM alpine:latest\r\nRUN apk update &#x26;&#x26; apk add ca-certificates bash sudo &#x26;&#x26; rm -rf /var/cache/apk/*\r\n\r\n# Azure allows SSH access to the container. This isn't needed for Tailscale to\r\n# operate, but is really useful for debugging the application.\r\nRUN apk add openssh openssh-keygen &#x26;&#x26; echo \"root:Docker!\" | chpasswd\r\nRUN apk add netcat-openbsd\r\nRUN mkdir -p /etc/ssh\r\nCOPY sshd_config /etc/ssh/\r\nEXPOSE 80 2222\r\n\r\n# Copy binary to production image.\r\nCOPY --from=builder /app/start.sh /app/start.sh\r\n# Change start.sh to be executable\r\nRUN chmod +x /app/start.sh\r\n\r\n# Copy Tailscale binaries from the tailscale image on Docker Hub.\r\nCOPY --from=docker.io/tailscale/tailscale:stable /usr/local/bin/tailscaled /app/tailscaled\r\nCOPY --from=docker.io/tailscale/tailscale:stable /usr/local/bin/tailscale /app/tailscale\r\nRUN mkdir -p /var/run/tailscale /var/cache/tailscale /var/lib/tailscale\r\n\r\n# Run on container startup.\r\nCMD [\"./app/start.sh\"]\n</code></pre>\n<p>The next time your Azure app deploys, it will be able to connect to your private Tailscale network.</p>\n<h2><a href=\"https://tailscale.com/docs/install/cloud/azure/azure-app-service#remove-ephemeral-nodes-from-a-tailnet\">Remove ephemeral nodes from a tailnet</a></h2>\n<p>When an ephemeral node goes offline, it is automatically removed from your tailnet. You can also control ephemeral node removal using the <a href=\"https://tailscale.com/docs/reference/tailscale-cli#logout\"><code>tailscale logout</code></a> command to either manually force the removal or incorporate the command into the <a href=\"https://tailscale.com/docs/reference/tailscaled\"><code>tailscaled</code></a> Tailscale daemon. For more information, refer to <a href=\"https://tailscale.com/docs/features/ephemeral-nodes#faq\">Ephemeral nodes</a>.</p>\n<p><img src=\"https://cdn.brandfetch.io/tailscale.com/fallback/lettermark/theme/dark/h/256/w/256/icon?c=1bfwsmEH20zzEfSNTed\" alt=\"Project Logo\"></p>\n<p>Ask AI</p>\n<p>reCAPTCHA</p>\n<p>Recaptcha requires verification.</p>\n<p>protected by <strong>reCAPTCHA</strong></p>\n"}