{"slug":"register-a-tsnet-application-as-a-tailscale-service","title":"Register a tsnet application as a Tailscale Service","tags":["tailscale"],"agent_summary":"Last validated: Jan 27, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Register a tsnet application as a Tailscale Service\r\n\r\nLast validated: Jan 27, 2026\r\n\r\n## [Introduction](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#introduction)\r\n\r\nIn this guide you will use the [`tsnet`](https://tailscale.com/docs/features/tsnet) package to register an application as a [Tailscale Service](https://tailscale.com/docs/features/tailscale-services) host. This pattern can be applied to other `tsnet` applications.\r\n\r\nThe example code for this demo is available in the [`tailscale/tailscale` repository](https://github.com/tailscale/tailscale/blob/v1.94.1/tsnet/example/tsnet-services/tsnet-services.go).\r\n\r\n## [Prerequisites](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#prerequisites)\r\n\r\nBefore you begin this guide you'll need the following:\r\n\r\n- The [Go compiler toolchain](https://go.dev/dl).\r\n- A terminal window (command prompt).\r\n- An active tailnet.\r\n- One or more devices running Tailscale v1.86.0 or later.\r\n- [Owner, Admin, or Network admin](https://tailscale.com/docs/reference/user-roles) account permissions.\r\n\r\n## [Step 1: Update your tailnet policy file](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#step-1-update-your-tailnet-policy-file)\r\n\r\nAdd `tagOwners`, `autoApprovers`, and `grants` to your tailnet policy file.\r\n\r\n### [Create a tag](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#create-a-tag)\r\n\r\nUse the Tailscale admin console to create a [Tailscale tag](https://tailscale.com/docs/features/tags).\r\n\r\n1. Open the [Access controls](https://login.tailscale.com/admin/acls) page of the admin console.\r\n\r\n2. Select the **Tags** pane.\r\n\r\n3. Select **Create tag**.\r\n\r\n4. Add the **Tag name**.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\ntsnet-demo-host\r\n```\r\n\r\n5. Add the **Tag owner**.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\nautogroup:member\r\n```\r\n\r\n6. Select **Save**.\r\n\r\n\r\n### [Define a service](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#define-a-service)\r\n\r\nUse the Tailscale admin console to add a Tailscale Service.\r\n\r\n1. Open the [Services](https://login.tailscale.com/admin/services) page of the admin console.\r\n\r\n2. Select the **Advertised** pane.\r\n\r\n3. Select **Define Service**.\r\n\r\n4. Add the **Service name**.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\ntsnet-demo\r\n```\r\n\r\n5. Add the **Ports**.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\n443\r\n```\r\n\r\n6. Select **Define Service**.\r\n\r\n\r\nFor the purposes of this example, the Service will not require a tag.\r\n\r\n### [Define auto approval](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#define-auto-approval)\r\n\r\nUse the Tailscale admin console to add auto approval.\r\n\r\n1. Open the [Access controls](https://login.tailscale.com/admin/acls) page of the admin console.\r\n\r\n2. Select the **Auto approvers** pane.\r\n\r\n3. Select the **Select service** dropdown and choose the example service.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\nsvc:tsnet-demo\r\n```\r\n\r\n4. Select the **Service can automatically accept devices** dropdown and choose the example tag.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\ntag:tsnet-demo-host\r\n```\r\n\r\n5. Select **Save service auto approver**.\r\n\r\n\r\n### [Define grants](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#define-grants)\r\n\r\nUse the Tailscale admin console to add grants.\r\n\r\n1. Open the [Access controls](https://login.tailscale.com/admin/acls) page of the admin console.\r\n\r\n2. Select the **General access rule** pane.\r\n\r\n3. Select **Add rule**.\r\n\r\n4. Add **All users and devices** for **Source**.\r\n\r\n5. Add the example service for **Destination**.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\nsvc:tsnet-demo\r\n```\r\n\r\n6. Add \\*\\*All ports and protocols\" for **Port and protocol**.\r\n\r\n7. Select **Save grant**.\r\n\r\n\r\n### [Example tailnet policy file](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#example-tailnet-policy-file)\r\n\r\nAt this point, your policy file should include:\r\n\r\n```json\r\n\"tagOwners\": {\r\n  \"tag:tsnet-demo-host\": [\"autogroup:member\"],\r\n},\r\n\"autoApprovers\": {\r\n  \"services\": {\r\n    \"svc:tsnet-demo\": [\"tag:tsnet-demo-host\"],\r\n  },\r\n},\r\n\"grants\": [\\\r\n  \"src\": [\"*\"],\\\r\n  \"dst\": [\"svc:tsnet-demo\"],\\\r\n  \"ip\": [\"*\"],\\\r\n],\r\n```\r\n\r\n## [Step 2: Generate an auth key](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#step-2-generate-an-auth-key)\r\n\r\nUse the Tailscale admin console to [generate an auth key](https://tailscale.com/docs/features/access-control/auth-keys#generate-an-auth-key).\r\n\r\n1. Open the [Keys](https://login.tailscale.com/admin/settings/keys) page of the admin console.\r\n2. Select **Generate auth key**.\r\n3. Enable **Tags**.\r\n4. Select **Add tags** and choose the example tag.\r\n5. Select **Generate key**.\r\n6. Copy the auth key to your clipboard for use later.\r\n7. Select **Done**.\r\n\r\nOpen a command terminal and save the auth key as an environment variable.\r\n\r\n```shell\r\nexport TS_AUTHKEY=<your-authkey>\r\n```\r\n\r\n## [Step 3: Use the `tsnet` package](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#step-3-use-the-tsnet-package)\r\n\r\n1. Open your text editor.\r\n2. Create a `tsnet-services.go` file:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"flag\"\r\n\t\"fmt\"\r\n\t\"log\"\r\n\t\"net/http\"\r\n\r\n\t\"tailscale.com/tsnet\"\r\n)\r\n\r\nvar (\r\n\tsvcName = flag.String(\"service\", \"\", \"the name of your Service, e.g. svc:tsnet-demo\")\r\n)\r\n\r\nfunc main() {\r\n\tflag.Parse()\r\n\tif *svcName == \"\" {\r\n\t\tlog.Fatal(\"a Service name must be provided\")\r\n\t}\r\n\r\n\ts := &tsnet.Server{\r\n\t\tHostname: \"tsnet-services-demo\",\r\n\t}\r\n\tdefer s.Close()\r\n\r\n\tln, err := s.ListenService(*svcName, tsnet.ServiceModeHTTP{\r\n\t\tHTTPS: true,\r\n\t\tPort:  443,\r\n\t})\r\n\tif err != nil {\r\n\t\tlog.Fatal(err)\r\n\t}\r\n\tdefer ln.Close()\r\n\r\n\tlog.Printf(\"Listening on https://%v\\n\", ln.FQDN)\r\n\r\n\terr = http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\r\n\t\tfmt.Fprintln(w, \"<html><body><h1>Hello, tailnet!</h1>\")\r\n\t}))\r\n\tlog.Fatal(err)\r\n}\r\n```\r\n\r\nIn this example program, you will create a `tsnet.Server` instance with the hostname `tsnet-services-demo`. This server acts as a virtual node on your tailnet. The program instructs the node to listen for HTTPS connections to a Service on port `443`. The listener uses the `tsnet` package's [`ListenService`](https://tailscale.com/docs/reference/tsnet-server-api#serverlistenservice) and `ServiceModeHTTP`. The program also uses the Go standard library's `net/http` package to run an HTTP server on top of the listener. When other nodes on the tailnet connect to the Service, those connections will be routed to the virtual node defined by this program.\r\n\r\n## [Step 4: Run the program](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#step-4-run-the-program)\r\n\r\n1. Run the command:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```shell\r\ngo run tsnet-services.go --service=svc:tsnet-demo\r\n```\r\n\r\n\r\n## [Step 5: Connect to the application](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#step-5-connect-to-the-application)\r\n\r\n1. Visit the example server:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```markup\r\nopen https://tsnet-demo.<your-tailnet-DNS-name>\r\n```\r\n\r\n\r\nFor more information about tailnet DNS names, refer to [tailnet name](https://tailscale.com/docs/concepts/tailnet-name#tailnet-dns-name).\r\n\r\n## [Conclusion](https://tailscale.com/docs/features/tsnet/how-to/register-service\\#conclusion)\r\n\r\nThis pattern can be applied to other `tsnet` applications as Tailscale Services hosts.\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>Register a tsnet application as a Tailscale Service</h1>\n<p>Last validated: Jan 27, 2026</p>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#introduction\">Introduction</a></h2>\n<p>In this guide you will use the <a href=\"https://tailscale.com/docs/features/tsnet\"><code>tsnet</code></a> package to register an application as a <a href=\"https://tailscale.com/docs/features/tailscale-services\">Tailscale Service</a> host. This pattern can be applied to other <code>tsnet</code> applications.</p>\n<p>The example code for this demo is available in the <a href=\"https://github.com/tailscale/tailscale/blob/v1.94.1/tsnet/example/tsnet-services/tsnet-services.go\"><code>tailscale/tailscale</code> repository</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#prerequisites\">Prerequisites</a></h2>\n<p>Before you begin this guide you'll need the following:</p>\n<ul>\n<li>The <a href=\"https://go.dev/dl\">Go compiler toolchain</a>.</li>\n<li>A terminal window (command prompt).</li>\n<li>An active tailnet.</li>\n<li>One or more devices running Tailscale v1.86.0 or later.</li>\n<li><a href=\"https://tailscale.com/docs/reference/user-roles\">Owner, Admin, or Network admin</a> account permissions.</li>\n</ul>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#step-1-update-your-tailnet-policy-file\">Step 1: Update your tailnet policy file</a></h2>\n<p>Add <code>tagOwners</code>, <code>autoApprovers</code>, and <code>grants</code> to your tailnet policy file.</p>\n<h3><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#create-a-tag\">Create a tag</a></h3>\n<p>Use the Tailscale admin console to create a <a href=\"https://tailscale.com/docs/features/tags\">Tailscale tag</a>.</p>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/acls\">Access controls</a> page of the admin console.</p>\n</li>\n<li>\n<p>Select the <strong>Tags</strong> pane.</p>\n</li>\n<li>\n<p>Select <strong>Create tag</strong>.</p>\n</li>\n<li>\n<p>Add the <strong>Tag name</strong>.</p>\n</li>\n</ol>\n<pre><code class=\"language-json\">tsnet-demo-host\n</code></pre>\n<ol start=\"5\">\n<li>Add the <strong>Tag owner</strong>.</li>\n</ol>\n<pre><code class=\"language-json\">autogroup:member\n</code></pre>\n<ol start=\"6\">\n<li>Select <strong>Save</strong>.</li>\n</ol>\n<h3><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#define-a-service\">Define a service</a></h3>\n<p>Use the Tailscale admin console to add a Tailscale Service.</p>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/services\">Services</a> page of the admin console.</p>\n</li>\n<li>\n<p>Select the <strong>Advertised</strong> pane.</p>\n</li>\n<li>\n<p>Select <strong>Define Service</strong>.</p>\n</li>\n<li>\n<p>Add the <strong>Service name</strong>.</p>\n</li>\n</ol>\n<pre><code class=\"language-json\">tsnet-demo\n</code></pre>\n<ol start=\"5\">\n<li>Add the <strong>Ports</strong>.</li>\n</ol>\n<pre><code class=\"language-json\">443\n</code></pre>\n<ol start=\"6\">\n<li>Select <strong>Define Service</strong>.</li>\n</ol>\n<p>For the purposes of this example, the Service will not require a tag.</p>\n<h3><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#define-auto-approval\">Define auto approval</a></h3>\n<p>Use the Tailscale admin console to add auto approval.</p>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/acls\">Access controls</a> page of the admin console.</p>\n</li>\n<li>\n<p>Select the <strong>Auto approvers</strong> pane.</p>\n</li>\n<li>\n<p>Select the <strong>Select service</strong> dropdown and choose the example service.</p>\n</li>\n</ol>\n<pre><code class=\"language-json\">svc:tsnet-demo\n</code></pre>\n<ol start=\"4\">\n<li>Select the <strong>Service can automatically accept devices</strong> dropdown and choose the example tag.</li>\n</ol>\n<pre><code class=\"language-json\">tag:tsnet-demo-host\n</code></pre>\n<ol start=\"5\">\n<li>Select <strong>Save service auto approver</strong>.</li>\n</ol>\n<h3><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#define-grants\">Define grants</a></h3>\n<p>Use the Tailscale admin console to add grants.</p>\n<ol>\n<li>\n<p>Open the <a href=\"https://login.tailscale.com/admin/acls\">Access controls</a> page of the admin console.</p>\n</li>\n<li>\n<p>Select the <strong>General access rule</strong> pane.</p>\n</li>\n<li>\n<p>Select <strong>Add rule</strong>.</p>\n</li>\n<li>\n<p>Add <strong>All users and devices</strong> for <strong>Source</strong>.</p>\n</li>\n<li>\n<p>Add the example service for <strong>Destination</strong>.</p>\n</li>\n</ol>\n<pre><code class=\"language-json\">svc:tsnet-demo\n</code></pre>\n<ol start=\"6\">\n<li>\n<p>Add **All ports and protocols\" for <strong>Port and protocol</strong>.</p>\n</li>\n<li>\n<p>Select <strong>Save grant</strong>.</p>\n</li>\n</ol>\n<h3><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#example-tailnet-policy-file\">Example tailnet policy file</a></h3>\n<p>At this point, your policy file should include:</p>\n<pre><code class=\"language-json\">\"tagOwners\": {\r\n  \"tag:tsnet-demo-host\": [\"autogroup:member\"],\r\n},\r\n\"autoApprovers\": {\r\n  \"services\": {\r\n    \"svc:tsnet-demo\": [\"tag:tsnet-demo-host\"],\r\n  },\r\n},\r\n\"grants\": [\\\r\n  \"src\": [\"*\"],\\\r\n  \"dst\": [\"svc:tsnet-demo\"],\\\r\n  \"ip\": [\"*\"],\\\r\n],\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#step-2-generate-an-auth-key\">Step 2: Generate an auth key</a></h2>\n<p>Use the Tailscale admin console to <a href=\"https://tailscale.com/docs/features/access-control/auth-keys#generate-an-auth-key\">generate an auth key</a>.</p>\n<ol>\n<li>Open the <a href=\"https://login.tailscale.com/admin/settings/keys\">Keys</a> page of the admin console.</li>\n<li>Select <strong>Generate auth key</strong>.</li>\n<li>Enable <strong>Tags</strong>.</li>\n<li>Select <strong>Add tags</strong> and choose the example tag.</li>\n<li>Select <strong>Generate key</strong>.</li>\n<li>Copy the auth key to your clipboard for use later.</li>\n<li>Select <strong>Done</strong>.</li>\n</ol>\n<p>Open a command terminal and save the auth key as an environment variable.</p>\n<pre><code class=\"language-shell\">export TS_AUTHKEY=&#x3C;your-authkey>\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#step-3-use-the-tsnet-package\">Step 3: Use the <code>tsnet</code> package</a></h2>\n<ol>\n<li>Open your text editor.</li>\n<li>Create a <code>tsnet-services.go</code> file:</li>\n</ol>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n\t\"flag\"\r\n\t\"fmt\"\r\n\t\"log\"\r\n\t\"net/http\"\r\n\r\n\t\"tailscale.com/tsnet\"\r\n)\r\n\r\nvar (\r\n\tsvcName = flag.String(\"service\", \"\", \"the name of your Service, e.g. svc:tsnet-demo\")\r\n)\r\n\r\nfunc main() {\r\n\tflag.Parse()\r\n\tif *svcName == \"\" {\r\n\t\tlog.Fatal(\"a Service name must be provided\")\r\n\t}\r\n\r\n\ts := &#x26;tsnet.Server{\r\n\t\tHostname: \"tsnet-services-demo\",\r\n\t}\r\n\tdefer s.Close()\r\n\r\n\tln, err := s.ListenService(*svcName, tsnet.ServiceModeHTTP{\r\n\t\tHTTPS: true,\r\n\t\tPort:  443,\r\n\t})\r\n\tif err != nil {\r\n\t\tlog.Fatal(err)\r\n\t}\r\n\tdefer ln.Close()\r\n\r\n\tlog.Printf(\"Listening on https://%v\\n\", ln.FQDN)\r\n\r\n\terr = http.Serve(ln, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\r\n\t\tfmt.Fprintln(w, \"&#x3C;html>&#x3C;body>&#x3C;h1>Hello, tailnet!&#x3C;/h1>\")\r\n\t}))\r\n\tlog.Fatal(err)\r\n}\n</code></pre>\n<p>In this example program, you will create a <code>tsnet.Server</code> instance with the hostname <code>tsnet-services-demo</code>. This server acts as a virtual node on your tailnet. The program instructs the node to listen for HTTPS connections to a Service on port <code>443</code>. The listener uses the <code>tsnet</code> package's <a href=\"https://tailscale.com/docs/reference/tsnet-server-api#serverlistenservice\"><code>ListenService</code></a> and <code>ServiceModeHTTP</code>. The program also uses the Go standard library's <code>net/http</code> package to run an HTTP server on top of the listener. When other nodes on the tailnet connect to the Service, those connections will be routed to the virtual node defined by this program.</p>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#step-4-run-the-program\">Step 4: Run the program</a></h2>\n<ol>\n<li>Run the command:</li>\n</ol>\n<pre><code class=\"language-shell\">go run tsnet-services.go --service=svc:tsnet-demo\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#step-5-connect-to-the-application\">Step 5: Connect to the application</a></h2>\n<ol>\n<li>Visit the example server:</li>\n</ol>\n<pre><code class=\"language-markup\">open https://tsnet-demo.&#x3C;your-tailnet-DNS-name>\n</code></pre>\n<p>For more information about tailnet DNS names, refer to <a href=\"https://tailscale.com/docs/concepts/tailnet-name#tailnet-dns-name\">tailnet name</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/tsnet/how-to/register-service#conclusion\">Conclusion</a></h2>\n<p>This pattern can be applied to other <code>tsnet</code> applications as Tailscale Services hosts.</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"}