{"slug":"tailscale-funnel-examples","title":"Tailscale Funnel examples","tags":["tailscale"],"agent_summary":"Last validated: Oct 14, 2025","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Tailscale Funnel examples\r\n\r\nLast validated: Oct 14, 2025\r\n\r\nBefore you try the examples in this topic, review the [Funnel documentation](https://tailscale.com/docs/features/tailscale-funnel) to make sure you meet the requirements.\r\n\r\nWith [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel), you can expose local services, folders, or text to the public internet over HTTPS. We've collected these examples from Tailscale users to inspire you to try it in new ways.\r\n\r\nYou can share nearly any HTTP or TCP service listening on your local device with Funnel. For example, you can share a web application demo with a client, test changes to a webhook receiver without waiting for a cloud service to converge on every change, or expose a development copy of your website to test [OpenGraph metadata changes](https://ogp.me/).\r\n\r\nThe following sections cover common use cases in more detail.\r\n\r\n## [Share a simple file server](https://tailscale.com/docs/reference/examples/funnel\\#share-a-simple-file-server)\r\n\r\nThe following example uses the [`tailscale funnel`](https://tailscale.com/docs/reference/tailscale-cli/funnel) command to create a simple file server. Using Funnel as a file server is often more efficient than transferring through a third-party service. It's also more convenient than using tools like Python's `http.server`.\r\n\r\nFirst, create some files to serve. This example creates the files from scratch, but you can also use existing files.\r\n\r\n```shell\r\nmkdir /tmp/public\r\necho \"Hello World\" > /tmp/public/hello.txt\r\necho \"Pangolin\" > /tmp/public/animal.txt\r\n```\r\n\r\nServe the files over the internet using Funnel:\r\n\r\n```shell\r\nsudo tailscale funnel /tmp/public\r\n```\r\n\r\nOn Windows, instead of using `sudo`, open the a command prompt as Administrator, then run:\r\n\r\n```shell\r\nc:\\Users\\Amelie> tailscale funnel c:\\tmp\\public\r\n```\r\n\r\nThe status confirms the previous command and provides the hostname that Funnel configures for the device.\r\n\r\n```shell\r\nsudo tailscale funnel /tmp/public\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / path /tmp/public\r\n\r\nPress Ctrl+C to exit.\r\n```\r\n\r\nYou can use `curl` to confirm the URLs work, but you should also be able to access the two files you created by visiting the Funnel URL in a browser. Requesting the `/public` folder returns a directory listing.\r\n\r\n```shell\r\ncurl -L https://amelie-workstation.pango-lin.ts.net\r\n<pre>\r\n<a href=\"animal.txt\">animal.txt</a>\r\n<a href=\"hello.txt\">hello.txt</a>\r\n</pre>\r\n\r\ncurl -L https://amelie-workstation.pango-lin.ts.net/animal.txt\r\nPangolin\r\n```\r\n\r\n## [Serve a static site](https://tailscale.com/docs/reference/examples/funnel\\#serve-a-static-site)\r\n\r\nThis example shows how to serve a static HTML website to the internet.\r\n\r\nTo get started, create some files as an example of what a static site would consist of (for example, an index file and some assets). You can also use one of the [many static site generators](https://github.com/myles/awesome-static-generators).\r\n\r\n`/tmp/static-site/index.html`\r\n\r\n```html\r\n<html>\r\n  <head>\r\n    <title>Hello World</title>\r\n    <link rel=\"stylesheet\" href=\"/styles.css\" />\r\n  </head>\r\n  <body>\r\n    <h1>Hello World</h1>\r\n  </body>\r\n</html>\r\n```\r\n\r\n`/tmp/static-site/styles.css`\r\n\r\n```css\r\n*,\r\nhtml {\r\n  margin: 0;\r\n  padding: 0;\r\n  box-sizing: border-box;\r\n  font-family: monospace;\r\n  font-size: 10vw;\r\n  text-transform: uppercase;\r\n}\r\n\r\nbody {\r\n  position: absolute;\r\n  left: 50%;\r\n  top: 25%;\r\n  transform: translate3d(-50%, -50%, 0);\r\n  overflow: hidden;\r\n}\r\n\r\nh1 {\r\n  position: relative;\r\n  top: 2em;\r\n  animation: slide-up 3s infinite;\r\n}\r\n\r\n@keyframes slide-up {\r\n  0% {\r\n    top: 2em;\r\n  }\r\n  50% {\r\n    top: 0em;\r\n  }\r\n  100% {\r\n    top: 2em;\r\n  }\r\n}\r\n```\r\n\r\nAfter you have your files, serve the static site to the internet:\r\n\r\n```shell\r\nsudo tailscale funnel /tmp/static-site\r\n```\r\n\r\nThe status confirms the previous command and provides the hostname that Funnel configures for this device.\r\n\r\n```shell\r\nsudo tailscale funnel /tmp/static-site\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / path /tmp/static-site\r\n\r\nPress Ctrl+C to exit.\r\n```\r\n\r\nYou can now open the URL in your browser to confirm everything is working.\r\n\r\n![A web page served over Tailscale as viewed in the browser.](https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ffunnel-hello-world.b88bb87e.png&w=1200&q=75)\r\n\r\n## [Expose a development server to the public](https://tailscale.com/docs/reference/examples/funnel\\#expose-a-development-server-to-the-public)\r\n\r\nA route accessible with Funnel means other internet users can interact with a local server on your device. For example, if you are working on a blog post and want to share a draft for review, you can make your development site publicly available with Funnel.\r\n\r\nIf you have a local HTTP server running on port `3000`, you can expose the local server to the internet over HTTPS with Funnel:\r\n\r\n```shell\r\nsudo tailscale funnel 3000\r\n```\r\n\r\nThe status confirms the previous command and provides the hostname that Funnel configures for this device.\r\n\r\n```shell\r\nsudo tailscale funnel 3000\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / proxy http://127.0.0.1:3000\r\n\r\nPress Ctrl+C to exit.\r\n```\r\n\r\nOpen the URL in your browser to confirm that everything is working correctly.\r\n\r\nAs long as your development machine is turned on and connected to Tailscale, the data will be routed to and from your development server with Funnel. Remember, Funnel uses relay servers to convey the encrypted data to and from your device. It does not allow devices on the internet to connect directly to your machine.\r\n\r\n## [Share a Funnel device](https://tailscale.com/docs/reference/examples/funnel\\#share-a-funnel-device)\r\n\r\nFunnels have a predictable, stable DNS name, like `amelie-workstation.pango-lin.ts.net.` This lets you set or share your DNS name one time. Then, it's accessible anytime you turn your Funnel on.\r\n\r\nTurn on Tailscale SSH to make Funnels easier to connect to.\r\n\r\nYou can also share the Funnel DNS name with multiple collaborators or colleagues. This is useful when configuring a backend like GitHub with a development webhook URL and wish to keep that URL stable, no matter which developer is currently testing the webhook APIs.\r\n\r\nYou can share a Funnel device with a custom name. For example, a Funnel that exposes GitHub webhooks might have a name like `github-hooks-dev.pango-lin.ts.net`.\r\n\r\nThe follow command tuns on the Funnel for port `8080`:\r\n\r\n```shell\r\nsudo tailscale funnel 8080\r\n```\r\n\r\nThis lets Funnel forward HTTPS traffic from any path to `http://localhost:8080`.\r\n\r\nStart your development server to test your webhooks from the other machines with which you wish to share the Funnel. The following example uses port `3000` as the local development server's port. Start an SSH reverse proxy connecting your local development server to the shared Funnel device. The Funnel device should be configured on its port `8080`, the Funnel's target. For example:\r\n\r\n```shell\r\nssh -NT -R 8080:127.0.0.1:3000 github-hook-dev.pango-lin.ts.net\r\n```\r\n\r\nYou can test your webhook or visit the URL `https://github-hook-dev.pango-lin.ts.net`. You can watch requests from the internet through your shared Funnel device to your local development server!\r\n\r\nIf a shared Funnel is already in use, Tailscale returns an error message when establishing the SSH reverse proxy.\r\n\r\n```shell\r\nWarning: remote port forwarding failed for listen port 8080\r\n```\r\n\r\n## [Test webhook receiver changes](https://tailscale.com/docs/reference/examples/funnel\\#test-webhook-receiver-changes)\r\n\r\nA route in Funnel means other services on the web can reach it. They can submit data, like webhooks, from vendors like GitHub or Stripe. Using Funnel lets you test your work faster than you could if you used a cloud deployment.\r\n\r\nYou can use Funnel to expose the webhook receiver on your development device. Then, use that URL for the service you are integrating with.\r\n\r\nIf you have a local HTTP server running on port `3000`, set up Funnel as a reverse proxy to that server:\r\n\r\n```shell\r\nsudo tailscale funnel 3000\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / proxy http://127.0.0.1:3000\r\n\r\nPress Ctrl+C to exit.\r\n```\r\n\r\nConfigure the other service to use your URL and webhook path as usual. You can trigger messages to your service like any other webhook receiver. If your development device is on and connected to Tailscale, the webhooks will be routed to your server with Funnel.\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>Tailscale Funnel examples</h1>\n<p>Last validated: Oct 14, 2025</p>\n<p>Before you try the examples in this topic, review the <a href=\"https://tailscale.com/docs/features/tailscale-funnel\">Funnel documentation</a> to make sure you meet the requirements.</p>\n<p>With <a href=\"https://tailscale.com/docs/features/tailscale-funnel\">Tailscale Funnel</a>, you can expose local services, folders, or text to the public internet over HTTPS. We've collected these examples from Tailscale users to inspire you to try it in new ways.</p>\n<p>You can share nearly any HTTP or TCP service listening on your local device with Funnel. For example, you can share a web application demo with a client, test changes to a webhook receiver without waiting for a cloud service to converge on every change, or expose a development copy of your website to test <a href=\"https://ogp.me/\">OpenGraph metadata changes</a>.</p>\n<p>The following sections cover common use cases in more detail.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/examples/funnel#share-a-simple-file-server\">Share a simple file server</a></h2>\n<p>The following example uses the <a href=\"https://tailscale.com/docs/reference/tailscale-cli/funnel\"><code>tailscale funnel</code></a> command to create a simple file server. Using Funnel as a file server is often more efficient than transferring through a third-party service. It's also more convenient than using tools like Python's <code>http.server</code>.</p>\n<p>First, create some files to serve. This example creates the files from scratch, but you can also use existing files.</p>\n<pre><code class=\"language-shell\">mkdir /tmp/public\r\necho \"Hello World\" > /tmp/public/hello.txt\r\necho \"Pangolin\" > /tmp/public/animal.txt\n</code></pre>\n<p>Serve the files over the internet using Funnel:</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel /tmp/public\n</code></pre>\n<p>On Windows, instead of using <code>sudo</code>, open the a command prompt as Administrator, then run:</p>\n<pre><code class=\"language-shell\">c:\\Users\\Amelie> tailscale funnel c:\\tmp\\public\n</code></pre>\n<p>The status confirms the previous command and provides the hostname that Funnel configures for the device.</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel /tmp/public\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / path /tmp/public\r\n\r\nPress Ctrl+C to exit.\n</code></pre>\n<p>You can use <code>curl</code> to confirm the URLs work, but you should also be able to access the two files you created by visiting the Funnel URL in a browser. Requesting the <code>/public</code> folder returns a directory listing.</p>\n<pre><code class=\"language-shell\">curl -L https://amelie-workstation.pango-lin.ts.net\r\n&#x3C;pre>\r\n&#x3C;a href=\"animal.txt\">animal.txt&#x3C;/a>\r\n&#x3C;a href=\"hello.txt\">hello.txt&#x3C;/a>\r\n&#x3C;/pre>\r\n\r\ncurl -L https://amelie-workstation.pango-lin.ts.net/animal.txt\r\nPangolin\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/reference/examples/funnel#serve-a-static-site\">Serve a static site</a></h2>\n<p>This example shows how to serve a static HTML website to the internet.</p>\n<p>To get started, create some files as an example of what a static site would consist of (for example, an index file and some assets). You can also use one of the <a href=\"https://github.com/myles/awesome-static-generators\">many static site generators</a>.</p>\n<p><code>/tmp/static-site/index.html</code></p>\n<pre><code class=\"language-html\">&#x3C;html>\r\n  &#x3C;head>\r\n    &#x3C;title>Hello World&#x3C;/title>\r\n    &#x3C;link rel=\"stylesheet\" href=\"/styles.css\" />\r\n  &#x3C;/head>\r\n  &#x3C;body>\r\n    &#x3C;h1>Hello World&#x3C;/h1>\r\n  &#x3C;/body>\r\n&#x3C;/html>\n</code></pre>\n<p><code>/tmp/static-site/styles.css</code></p>\n<pre><code class=\"language-css\">*,\r\nhtml {\r\n  margin: 0;\r\n  padding: 0;\r\n  box-sizing: border-box;\r\n  font-family: monospace;\r\n  font-size: 10vw;\r\n  text-transform: uppercase;\r\n}\r\n\r\nbody {\r\n  position: absolute;\r\n  left: 50%;\r\n  top: 25%;\r\n  transform: translate3d(-50%, -50%, 0);\r\n  overflow: hidden;\r\n}\r\n\r\nh1 {\r\n  position: relative;\r\n  top: 2em;\r\n  animation: slide-up 3s infinite;\r\n}\r\n\r\n@keyframes slide-up {\r\n  0% {\r\n    top: 2em;\r\n  }\r\n  50% {\r\n    top: 0em;\r\n  }\r\n  100% {\r\n    top: 2em;\r\n  }\r\n}\n</code></pre>\n<p>After you have your files, serve the static site to the internet:</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel /tmp/static-site\n</code></pre>\n<p>The status confirms the previous command and provides the hostname that Funnel configures for this device.</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel /tmp/static-site\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / path /tmp/static-site\r\n\r\nPress Ctrl+C to exit.\n</code></pre>\n<p>You can now open the URL in your browser to confirm everything is working.</p>\n<p><img src=\"https://tailscale.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Ffunnel-hello-world.b88bb87e.png&#x26;w=1200&#x26;q=75\" alt=\"A web page served over Tailscale as viewed in the browser.\"></p>\n<h2><a href=\"https://tailscale.com/docs/reference/examples/funnel#expose-a-development-server-to-the-public\">Expose a development server to the public</a></h2>\n<p>A route accessible with Funnel means other internet users can interact with a local server on your device. For example, if you are working on a blog post and want to share a draft for review, you can make your development site publicly available with Funnel.</p>\n<p>If you have a local HTTP server running on port <code>3000</code>, you can expose the local server to the internet over HTTPS with Funnel:</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel 3000\n</code></pre>\n<p>The status confirms the previous command and provides the hostname that Funnel configures for this device.</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel 3000\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / proxy http://127.0.0.1:3000\r\n\r\nPress Ctrl+C to exit.\n</code></pre>\n<p>Open the URL in your browser to confirm that everything is working correctly.</p>\n<p>As long as your development machine is turned on and connected to Tailscale, the data will be routed to and from your development server with Funnel. Remember, Funnel uses relay servers to convey the encrypted data to and from your device. It does not allow devices on the internet to connect directly to your machine.</p>\n<h2><a href=\"https://tailscale.com/docs/reference/examples/funnel#share-a-funnel-device\">Share a Funnel device</a></h2>\n<p>Funnels have a predictable, stable DNS name, like <code>amelie-workstation.pango-lin.ts.net.</code> This lets you set or share your DNS name one time. Then, it's accessible anytime you turn your Funnel on.</p>\n<p>Turn on Tailscale SSH to make Funnels easier to connect to.</p>\n<p>You can also share the Funnel DNS name with multiple collaborators or colleagues. This is useful when configuring a backend like GitHub with a development webhook URL and wish to keep that URL stable, no matter which developer is currently testing the webhook APIs.</p>\n<p>You can share a Funnel device with a custom name. For example, a Funnel that exposes GitHub webhooks might have a name like <code>github-hooks-dev.pango-lin.ts.net</code>.</p>\n<p>The follow command tuns on the Funnel for port <code>8080</code>:</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel 8080\n</code></pre>\n<p>This lets Funnel forward HTTPS traffic from any path to <code>http://localhost:8080</code>.</p>\n<p>Start your development server to test your webhooks from the other machines with which you wish to share the Funnel. The following example uses port <code>3000</code> as the local development server's port. Start an SSH reverse proxy connecting your local development server to the shared Funnel device. The Funnel device should be configured on its port <code>8080</code>, the Funnel's target. For example:</p>\n<pre><code class=\"language-shell\">ssh -NT -R 8080:127.0.0.1:3000 github-hook-dev.pango-lin.ts.net\n</code></pre>\n<p>You can test your webhook or visit the URL <code>https://github-hook-dev.pango-lin.ts.net</code>. You can watch requests from the internet through your shared Funnel device to your local development server!</p>\n<p>If a shared Funnel is already in use, Tailscale returns an error message when establishing the SSH reverse proxy.</p>\n<pre><code class=\"language-shell\">Warning: remote port forwarding failed for listen port 8080\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/reference/examples/funnel#test-webhook-receiver-changes\">Test webhook receiver changes</a></h2>\n<p>A route in Funnel means other services on the web can reach it. They can submit data, like webhooks, from vendors like GitHub or Stripe. Using Funnel lets you test your work faster than you could if you used a cloud deployment.</p>\n<p>You can use Funnel to expose the webhook receiver on your development device. Then, use that URL for the service you are integrating with.</p>\n<p>If you have a local HTTP server running on port <code>3000</code>, set up Funnel as a reverse proxy to that server:</p>\n<pre><code class=\"language-shell\">sudo tailscale funnel 3000\r\nAvailable on the internet:\r\nhttps://amelie-workstation.pango-lin.ts.net\r\n\r\n|-- / proxy http://127.0.0.1:3000\r\n\r\nPress Ctrl+C to exit.\n</code></pre>\n<p>Configure the other service to use your URL and webhook path as usual. You can trigger messages to your service like any other webhook receiver. If your development device is on and connected to Tailscale, the webhooks will be routed to your server with Funnel.</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"}