{"slug":"smaller-binaries-for-embedded-devices","title":"Smaller binaries for embedded devices","tags":["tailscale","devices"],"agent_summary":"Last validated: Jan 5, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Smaller binaries for embedded devices\r\n\r\nLast validated: Jan 5, 2026\r\n\r\nTailscale provides downloads for a variety of operating systems and\r\narchitectures on our [downloads page](https://tailscale.com/download). However, there are cases\r\nwhere you may want to build an \"extra-small\" Tailscale binary—one that\r\ntakes up a minimal amount of disk space. One common use case is building for an\r\nembedded device like an OpenWrt router.\r\n\r\n## [Prerequisites](https://tailscale.com/docs/how-to/set-up-small-tailscale\\#prerequisites)\r\n\r\nBefore you begin this guide, you'll need to have a Go development environment\r\nalready set up and working.\r\n\r\n## [Step 1: Building Tailscale](https://tailscale.com/docs/how-to/set-up-small-tailscale\\#step-1-building-tailscale)\r\n\r\nFirst, you can build a version of Tailscale that embeds both the client (the\r\n`tailscale` binary) and the daemon (the `tailscaled` binary) into a single\r\nbinary. This is similar to how tools like `busybox` work, where the behavior\r\nof the binary depends on how it's called (specifically, the value of\r\n`argv[0]`). Essentially: if the file on-disk is named `tailscale`, then the\r\nbinary will behave like the `tailscale` binary, and if it's named `tailscaled`,\r\nthen it'll behave like `tailscaled`.\r\n\r\nIn the [Tailscale repository](https://github.com/tailscale/tailscale):\r\n\r\n```shell\r\ngo build -o tailscale.combined -tags ts_include_cli ./cmd/tailscaled\r\n```\r\n\r\nUse the `du` (disk usage) command to check the compiled binary size:\r\n\r\n```shell\r\ndu -hs tailscale.combined\r\n```\r\n\r\nThe actual size of the output binary will depend on the version of Tailscale\r\nand the operating system and architecture it's being built for. Exact sizes are\r\nonly for illustrative purposes.\r\n\r\nBy creating symlinks to the combined binary, you can run it as both\r\nthe daemon and the CLI:\r\n\r\n```shell\r\nln -s tailscale.combined tailscale\r\nln -s tailscale.combined tailscaled\r\n```\r\n\r\nTest your `tailscale` symlink with the `--help` flag:\r\n\r\n```shell\r\n./tailscale --help\r\n```\r\n\r\nThis command should return the help information:\r\n\r\n```shell\r\nUSAGE\r\n  tailscale [flags] <subcommand> [command flags]\r\n\r\nFor help on subcommands, add --help after: \"tailscale status --help\".\r\n # ... omitted ...\r\n```\r\n\r\nTest your `tailscaled` symlink with the `--help` flag:\r\n\r\n```shell\r\n./tailscaled --help\r\n```\r\n\r\nThis command should return the help information:\r\n\r\n```shell\r\nUsage of ./tailscaled:\r\n  -bird-socket string\r\n        path of the bird unix socket\r\n  -cleanup\r\n        clean up system state and exit\r\n # ... omitted ...\r\n```\r\n\r\n## [Step 2: Building a smaller Tailscale binary](https://tailscale.com/docs/how-to/set-up-small-tailscale\\#step-2-building-a-smaller-tailscale-binary)\r\n\r\nIn addition to combining both the Tailscale client and daemon into the same\r\nbinary, you can also use the `--extra-small` flag to omit things like debug information and lesser\r\nused features from the built binary.\r\n\r\n```shell\r\nbuild_dist.sh --extra-small\r\n```\r\n\r\n## [Step 3: Compressing Tailscale](https://tailscale.com/docs/how-to/set-up-small-tailscale\\#step-3-compressing-tailscale)\r\n\r\nIn cases where disk space is a premium, one of the more effective options is to\r\nuse compression. There's a class of tools called \"packers\", which compress a\r\nbinary on-disk and restore the original uncompressed version of the binary\r\nwhen it is run.\r\n\r\n**Using a packer can be dangerous!** These tools fundamentally change how a\r\nbinary interacts with the operating system in ways that can reduce that\r\nbinary's security. It's beyond the scope of this guide to go into the full\r\ndetails, but as a specific example, most packers require that [W^X protection](https://en.wikipedia.org/wiki/W%5EX) be turned off or an executable temporary directory to\r\nfunction.\r\n\r\nAlso, some antivirus software will treat packed binaries as malicious, since this\r\ntechnique is often used by malware to obfuscate what it's doing.\r\n\r\nIn the case where it's necessary, though, the resulting space savings can be\r\nimpressive. Perhaps the most well-known packer is [UPX](https://upx.github.io/), and it can be\r\nused to compress the Tailscale combined binary that we built above.\r\n\r\n```shell\r\ngo build -o tailscale.combined -tags ts_include_cli -ldflags=\"-s -w\" ./cmd/tailscaled\r\n```\r\n\r\nUse the `du` command to check the compiled binary size:\r\n\r\n```shell\r\ndu -hs tailscale.combined\r\n```\r\n\r\nFor example, this returned the following size:\r\n\r\n```shell\r\n 18M    tailscale.combined\r\n```\r\n\r\nNext use the `upx` command:\r\n\r\n```shell\r\nupx --lzma --best ./tailscale.combined\r\n```\r\n\r\nUse the `du` command to check the compiled binary size:\r\n\r\n```shell\r\ndu -hs tailscale.combined\r\n```\r\n\r\nFor example, this returned the following compressed size:\r\n\r\n```shell\r\n 4.5M   tailscale.combined\r\n```\r\n\r\nAfter UPX compression, we've reduced the size of the (combined) Tailscale\r\nbinary from the original size of 23MiB down to only 4.5MiB, about 20% of the\r\noriginal size!\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>Smaller binaries for embedded devices</h1>\n<p>Last validated: Jan 5, 2026</p>\n<p>Tailscale provides downloads for a variety of operating systems and\r\narchitectures on our <a href=\"https://tailscale.com/download\">downloads page</a>. However, there are cases\r\nwhere you may want to build an \"extra-small\" Tailscale binary—one that\r\ntakes up a minimal amount of disk space. One common use case is building for an\r\nembedded device like an OpenWrt router.</p>\n<h2><a href=\"https://tailscale.com/docs/how-to/set-up-small-tailscale#prerequisites\">Prerequisites</a></h2>\n<p>Before you begin this guide, you'll need to have a Go development environment\r\nalready set up and working.</p>\n<h2><a href=\"https://tailscale.com/docs/how-to/set-up-small-tailscale#step-1-building-tailscale\">Step 1: Building Tailscale</a></h2>\n<p>First, you can build a version of Tailscale that embeds both the client (the\r\n<code>tailscale</code> binary) and the daemon (the <code>tailscaled</code> binary) into a single\r\nbinary. This is similar to how tools like <code>busybox</code> work, where the behavior\r\nof the binary depends on how it's called (specifically, the value of\r\n<code>argv[0]</code>). Essentially: if the file on-disk is named <code>tailscale</code>, then the\r\nbinary will behave like the <code>tailscale</code> binary, and if it's named <code>tailscaled</code>,\r\nthen it'll behave like <code>tailscaled</code>.</p>\n<p>In the <a href=\"https://github.com/tailscale/tailscale\">Tailscale repository</a>:</p>\n<pre><code class=\"language-shell\">go build -o tailscale.combined -tags ts_include_cli ./cmd/tailscaled\n</code></pre>\n<p>Use the <code>du</code> (disk usage) command to check the compiled binary size:</p>\n<pre><code class=\"language-shell\">du -hs tailscale.combined\n</code></pre>\n<p>The actual size of the output binary will depend on the version of Tailscale\r\nand the operating system and architecture it's being built for. Exact sizes are\r\nonly for illustrative purposes.</p>\n<p>By creating symlinks to the combined binary, you can run it as both\r\nthe daemon and the CLI:</p>\n<pre><code class=\"language-shell\">ln -s tailscale.combined tailscale\r\nln -s tailscale.combined tailscaled\n</code></pre>\n<p>Test your <code>tailscale</code> symlink with the <code>--help</code> flag:</p>\n<pre><code class=\"language-shell\">./tailscale --help\n</code></pre>\n<p>This command should return the help information:</p>\n<pre><code class=\"language-shell\">USAGE\r\n  tailscale [flags] &#x3C;subcommand> [command flags]\r\n\r\nFor help on subcommands, add --help after: \"tailscale status --help\".\r\n # ... omitted ...\n</code></pre>\n<p>Test your <code>tailscaled</code> symlink with the <code>--help</code> flag:</p>\n<pre><code class=\"language-shell\">./tailscaled --help\n</code></pre>\n<p>This command should return the help information:</p>\n<pre><code class=\"language-shell\">Usage of ./tailscaled:\r\n  -bird-socket string\r\n        path of the bird unix socket\r\n  -cleanup\r\n        clean up system state and exit\r\n # ... omitted ...\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/how-to/set-up-small-tailscale#step-2-building-a-smaller-tailscale-binary\">Step 2: Building a smaller Tailscale binary</a></h2>\n<p>In addition to combining both the Tailscale client and daemon into the same\r\nbinary, you can also use the <code>--extra-small</code> flag to omit things like debug information and lesser\r\nused features from the built binary.</p>\n<pre><code class=\"language-shell\">build_dist.sh --extra-small\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/how-to/set-up-small-tailscale#step-3-compressing-tailscale\">Step 3: Compressing Tailscale</a></h2>\n<p>In cases where disk space is a premium, one of the more effective options is to\r\nuse compression. There's a class of tools called \"packers\", which compress a\r\nbinary on-disk and restore the original uncompressed version of the binary\r\nwhen it is run.</p>\n<p><strong>Using a packer can be dangerous!</strong> These tools fundamentally change how a\r\nbinary interacts with the operating system in ways that can reduce that\r\nbinary's security. It's beyond the scope of this guide to go into the full\r\ndetails, but as a specific example, most packers require that <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X protection</a> be turned off or an executable temporary directory to\r\nfunction.</p>\n<p>Also, some antivirus software will treat packed binaries as malicious, since this\r\ntechnique is often used by malware to obfuscate what it's doing.</p>\n<p>In the case where it's necessary, though, the resulting space savings can be\r\nimpressive. Perhaps the most well-known packer is <a href=\"https://upx.github.io/\">UPX</a>, and it can be\r\nused to compress the Tailscale combined binary that we built above.</p>\n<pre><code class=\"language-shell\">go build -o tailscale.combined -tags ts_include_cli -ldflags=\"-s -w\" ./cmd/tailscaled\n</code></pre>\n<p>Use the <code>du</code> command to check the compiled binary size:</p>\n<pre><code class=\"language-shell\">du -hs tailscale.combined\n</code></pre>\n<p>For example, this returned the following size:</p>\n<pre><code class=\"language-shell\"> 18M    tailscale.combined\n</code></pre>\n<p>Next use the <code>upx</code> command:</p>\n<pre><code class=\"language-shell\">upx --lzma --best ./tailscale.combined\n</code></pre>\n<p>Use the <code>du</code> command to check the compiled binary size:</p>\n<pre><code class=\"language-shell\">du -hs tailscale.combined\n</code></pre>\n<p>For example, this returned the following compressed size:</p>\n<pre><code class=\"language-shell\"> 4.5M   tailscale.combined\n</code></pre>\n<p>After UPX compression, we've reduced the size of the (combined) Tailscale\r\nbinary from the original size of 23MiB down to only 4.5MiB, about 20% of the\r\noriginal size!</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"}