Files
dashy/docs/authentication/tailscale/index.html
2026-07-04 17:15:02 +00:00

173 lines
78 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-authentication/tailscale" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.10.1">
<title data-rh="true">Tailscale | Dashy</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="keywords" content="dashy, dashboard, homelab, self-hosted, docker, homepage"><meta data-rh="true" property="og:type" content="website"><meta data-rh="true" property="og:url" content="https://dashy.to"><meta data-rh="true" property="og:image" content="https://dashy.to/img/dashy.png"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" name="twitter:title" content="Dashy — The Ultimate Homepage for your Homelab"><meta data-rh="true" name="twitter:description" content="Dashy is a self-hosted dashboard app for your homelab. Manage all your services, with status checks, widgets, themes and more."><meta data-rh="true" name="twitter:image" content="https://dashy.to/img/dashy.png"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Tailscale | Dashy"><meta data-rh="true" name="description" content="Tailscale is a popular way to put Dashy on a private network you can reach from your phone, laptop, or any other device you&#x27;ve added to your tailnet, without exposing it to the public internet. With Tailscale Serve in front, requests reaching Dashy already carry the user&#x27;s identity in HTTP headers, which plugs straight into Dashy&#x27;s header auth for auto-login."><meta data-rh="true" property="og:description" content="Tailscale is a popular way to put Dashy on a private network you can reach from your phone, laptop, or any other device you&#x27;ve added to your tailnet, without exposing it to the public internet. With Tailscale Serve in front, requests reaching Dashy already carry the user&#x27;s identity in HTTP headers, which plugs straight into Dashy&#x27;s header auth for auto-login."><link data-rh="true" rel="icon" href="/img/favicon.ico"><link data-rh="true" rel="canonical" href="https://dashy.to/docs/authentication/tailscale"><link data-rh="true" rel="alternate" href="https://dashy.to/docs/authentication/tailscale" hreflang="en"><link data-rh="true" rel="alternate" href="https://dashy.to/docs/authentication/tailscale" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Authentication","item":"https://dashy.to/docs/authentication"},{"@type":"ListItem","position":2,"name":"Tailscale","item":"https://dashy.to/docs/authentication/tailscale"}]}</script><link rel="preconnect" href="https://pixelflare.cc">
<link rel="preconnect" href="https://cdn.as93.net">
<link rel="dns-prefetch" href="https://api.github.com">
<link rel="dns-prefetch" href="https://no-track.as93.net">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"Dashy","url":"https://dashy.to","description":"The Ultimate Homepage for your Homelab","publisher":{"@type":"Person","name":"Alicia Sykes","url":"https://aliciasykes.com"}}</script>
<link rel="manifest" href="/manifest.json">
<link rel="alternate" type="application/rss+xml" title="Dashy — Releases &amp; Updates" href="/rss.xml">
<meta name="theme-color" content="#54bff7">
<script src="https://no-track.as93.net/js/script.js" defer="defer" data-domain="dashy.to"></script><link rel="stylesheet" href="/assets/css/styles.283a0681.css">
<script src="/assets/js/runtime~main.17c323d8.js" defer="defer"></script>
<script src="/assets/js/main.249792b4.js" defer="defer"></script>
</head>
<body>
<svg style="display: none;"><defs>
<symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol>
</defs></svg>
<script>!function(){var t=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();document.documentElement.setAttribute("data-theme",t||"dark"),document.documentElement.setAttribute("data-theme-choice",t||"dark")}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><div class="banner_woPo"><a class="link_ecgS" title="View the changelog, to see what&#x27;s new!" href="/updates">Dashy <!-- -->V4.3.15<!-- --> is now live 🚀</a><a class="link2_y3x6" title="View the changelog, to see what&#x27;s new!" href="/updates">See what&#x27;s new…</a><button class="closeBtn_fC0A" title="Dismiss update, and don&#x27;t show again" aria-label="Dismiss update, and don&#x27;t show again">×</button></div><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="theme-layout-navbar navbar navbar--fixed-top"><div class="navbar__inner"><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="/img/dashy.png" alt="Dashy Logo" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src="/img/dashy.png" alt="Dashy Logo" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><b class="navbar__title text--truncate">Dashy</b></a><a href="https://github.com/lissy93/dashy" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><a href="https://demo.dashy.to" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Live Demo<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a><a class="navbar__item navbar__link" href="/docs/quick-start">Quick Start</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs">Documentation</a><a class="navbar__item navbar__link" href="/api">API</a><a class="navbar__item navbar__link" href="/updates">Changelog</a></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="system mode" aria-label="Switch between dark and light mode (currently system mode)"><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" class="toggleIcon_g3eP systemToggleIcon_QzmC"><path fill="currentColor" d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"></path></svg></button></div><div class="navbarSearchContainer_Bca1"><div class="navbar__search searchBarContainer_NW3z" dir="ltr"><input placeholder="Search" aria-label="Search" class="navbar__search-input searchInput_YFbd" value=""><div class="loadingRing_RJI3 searchBarLoadingRing_YnHq"><div></div><div></div><div></div><div></div></div></div></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="theme-layout-main main-wrapper mainWrapper_z2l0"><div class="docsWrapper_hBAB"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docRoot_UBD9"><aside class="theme-doc-sidebar-container docSidebarContainer_YfHR"><div class="sidebarViewport_aRkj"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/quick-start"><span title="Running Dashy" class="categoryLinkLabel_W154">Running Dashy</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" href="/docs/icons"><span title="Feature Docs" class="categoryLinkLabel_W154">Feature Docs</span></a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/icons"><span title="Icons" class="linkLabel_WmDU">Icons</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/widgets"><span title="Widgets" class="linkLabel_WmDU">Widgets</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/theming"><span title="Theming" class="linkLabel_WmDU">Theming</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/status-indicators"><span title="Status Indicators" class="linkLabel_WmDU">Status Indicators</span></a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--active" tabindex="0" href="/docs/authentication"><span title="Authentication" class="categoryLinkLabel_W154">Authentication</span></a><button aria-label="Collapse sidebar category &#x27;Authentication&#x27;" aria-expanded="true" type="button" class="clean-btn menu__caret"></button></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/authelia-oidc"><span title="Authelia OIDC" class="linkLabel_WmDU">Authelia OIDC</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/authentik"><span title="Authentik OIDC" class="linkLabel_WmDU">Authentik OIDC</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/built-in"><span title="Built-In Auth" class="linkLabel_WmDU">Built-In Auth</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/cloudflare-tunnel"><span title="Cloudflare Tunnel" class="linkLabel_WmDU">Cloudflare Tunnel</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/header-auth"><span title="Header Authentication" class="linkLabel_WmDU">Header Authentication</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/keycloak"><span title="Keycloak" class="linkLabel_WmDU">Keycloak</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/oidc"><span title="OIDC" class="linkLabel_WmDU">OIDC</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/other-auth-methods"><span title="Other Auth Methods" class="linkLabel_WmDU">Other Auth Methods</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/pocketid"><span title="Pocket ID OIDC" class="linkLabel_WmDU">Pocket ID OIDC</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/docs/authentication/tailscale"><span title="Tailscale" class="linkLabel_WmDU">Tailscale</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-3 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/authentication/zitadel"><span title="Zitadel OIDC" class="linkLabel_WmDU">Zitadel OIDC</span></a></li></ul></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/searching"><span title="Search &amp; Shortcuts" class="linkLabel_WmDU">Search &amp; Shortcuts</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/alternate-views"><span title="Alternate Views &amp; Opening Methods" class="linkLabel_WmDU">Alternate Views &amp; Opening Methods</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/multi-language-support"><span title="Internationalization" class="linkLabel_WmDU">Internationalization</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/backup-restore"><span title="Cloud Backup and Restore" class="linkLabel_WmDU">Cloud Backup and Restore</span></a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/docs/pages-and-sections"><span title="Pages and Sections" class="linkLabel_WmDU">Pages and Sections</span></a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/showcase"><span title="Community" class="categoryLinkLabel_W154">Community</span></a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="categoryLink_byQd menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/docs/privacy"><span title="Misc" class="categoryLinkLabel_W154">Misc</span></a></div></li></ul></nav></div><div class="sidebar-ad"><script async="" src="//cdn.carbonads.com/carbon.js?serve=CWYIC53L&amp;placement=dashyto" id="_carbonads_js"></script></div></div></aside><main class="docMainContainer_TBSr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="docItemContainer_Djhp"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_Z_bl" aria-label="Breadcrumbs"><ul class="breadcrumbs"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YNFT"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">Feature Docs</span></li><li class="breadcrumbs__item"><a class="breadcrumbs__link" href="/docs/authentication"><span>Authentication</span></a></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">Tailscale</span></li></ul></nav><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Tailscale</h1></header>
<p><a href="https://tailscale.com/" target="_blank" rel="noopener noreferrer" class="">Tailscale</a> is a popular way to put Dashy on a private network you can reach from your phone, laptop, or any other device you&#x27;ve added to your tailnet, without exposing it to the public internet. With Tailscale Serve in front, requests reaching Dashy already carry the user&#x27;s identity in HTTP headers, which plugs straight into Dashy&#x27;s header auth for auto-login.</p>
<p><a href="https://github.com/juanfont/headscale" target="_blank" rel="noopener noreferrer" class="">Headscale</a> is a self-hosted control plane that speaks the same protocol. Everything in this guide works with both. There&#x27;s a short section near the end on what changes when you swap Tailscale&#x27;s coordination server for your own Headscale instance.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="contents">Contents<a href="#contents" class="hash-link" aria-label="Direct link to Contents" title="Direct link to Contents" translate="no"></a></h3>
<ul>
<li class=""><a href="#how-it-fits-together" class="">How it fits together</a></li>
<li class=""><a href="#prepare-tailscale" class="">Prepare Tailscale</a></li>
<li class=""><a href="#run-tailscale--dashy-together" class="">Run Tailscale + Dashy together</a></li>
<li class=""><a href="#configure-dashy" class="">Configure Dashy</a></li>
<li class=""><a href="#funnel-for-public-access-optional" class="">Funnel for public access</a></li>
<li class=""><a href="#using-headscale-instead" class="">Using Headscale instead</a></li>
<li class=""><a href="#best-practices" class="">Best practices</a></li>
<li class=""><a href="#troubleshooting-common-tailscale-issues" class="">Troubleshooting</a></li>
<li class=""><a href="#how-it-works" class="">How it Works</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-fits-together">How it fits together<a href="#how-it-fits-together" class="hash-link" aria-label="Direct link to How it fits together" title="Direct link to How it fits together" translate="no"></a></h2>
<!-- -->
<p>The pieces:</p>
<ul>
<li class=""><code>tailscaled</code> runs alongside Dashy, joins your tailnet, and obtains a free HTTPS cert for your tailnet hostname</li>
<li class="">Tailscale Serve terminates HTTPS and reverse-proxies to Dashy, adding <code>Tailscale-User-Login</code>, <code>Tailscale-User-Name</code>, and <code>Tailscale-User-Profile-Pic</code> headers describing the authenticated tailnet user</li>
<li class="">Dashy&#x27;s header auth reads <code>Tailscale-User-Login</code> and matches it to a configured user</li>
<li class="">Traffic between user devices and your host runs over WireGuard, peer-to-peer where possible. Tailscale&#x27;s control plane only mediates key exchange and routing, not the data itself</li>
</ul>
<p>You need:</p>
<ul>
<li class="">A Tailscale account (free plan covers 100 devices and 3 users)</li>
<li class="">An auth key, generated in the admin console</li>
<li class="">Docker</li>
<li class="">MagicDNS and HTTPS certificates both enabled in your tailnet settings (both on by default)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="prepare-tailscale">Prepare Tailscale<a href="#prepare-tailscale" class="hash-link" aria-label="Direct link to Prepare Tailscale" title="Direct link to Prepare Tailscale" translate="no"></a></h2>
<ol>
<li class="">Sign in to <a href="https://login.tailscale.com/admin" target="_blank" rel="noopener noreferrer" class="">the Tailscale admin console</a></li>
<li class="">Open <strong>DNS</strong> and confirm <strong>MagicDNS</strong> is on, and <strong>HTTPS Certificates</strong> is on. Both are required for Tailscale Serve</li>
<li class="">Open <strong>Settings &gt; Keys &gt; Generate auth key</strong></li>
<li class="">Pick <strong>Reusable: no</strong>, <strong>Ephemeral: no</strong>, <strong>Pre-approved: yes</strong>, optionally tag with <code>tag:container</code></li>
<li class="">Copy the key (<code>tskey-auth-...</code>). You&#x27;ll paste it into a <code>.env</code> next to the compose file</li>
</ol>
<p>Note your tailnet&#x27;s domain (something like <code>tail123abc.ts.net</code>). Your Dashy host will get a hostname under it once the container starts, e.g. <code>dashy.tail123abc.ts.net</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="run-tailscale--dashy-together">Run Tailscale + Dashy together<a href="#run-tailscale--dashy-together" class="hash-link" aria-label="Direct link to Run Tailscale + Dashy together" title="Direct link to Run Tailscale + Dashy together" translate="no"></a></h2>
<p>The Tailscale container shares its network namespace with Dashy, so the daemon listens on the tailnet and proxies to <code>127.0.0.1:8080</code> (Dashy in the same namespace).</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>Example <code>docker-compose.yml</code></summary><div><div class="collapsibleContent_i85q">
<!-- -->
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> dashy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">tailscale</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">services</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">tailscale</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> tailscale/tailscale</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">latest</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">hostname</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> dashy</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">restart</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> unless</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">stopped</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">environment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">TS_AUTHKEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain">TS_AUTHKEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">?</span><span class="token plain">ephemeral=false</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">TS_STATE_DIR</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> /var/lib/tailscale</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">TS_SERVE_CONFIG</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> /config/serve.json</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">TS_USERSPACE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;false&quot;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">TS_EXTRA_ARGS</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">advertise</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">tags=tag</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">container</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> ./ts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">state</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">/var/lib/tailscale</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> ./ts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">config</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">/config</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> /dev/net/tun</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">/dev/net/tun</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">cap_add</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> net_admin</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> sys_module</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">dashy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> lissy93/dashy</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">4.1.5</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">restart</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> unless</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">stopped</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">network_mode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> service</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">tailscale</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">environment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">NODE_ENV</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> production</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">HOST</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> 0.0.0.0</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">PORT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token number">8080</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> ./user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">/app/user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">data</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">depends_on</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">tailscale</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">condition</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> service_started</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">healthcheck</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">test</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">&quot;CMD-SHELL&quot;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;wget -qO- http://127.0.0.1:8080/healthz &gt;/dev/null 2&gt;&amp;1&quot;</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">interval</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> 10s</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">timeout</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> 5s</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">retries</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token number">10</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">start_period</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> 30s</span><br></div></code></pre></div></div>
</div></div></details>
<p><code>.env</code> next to the compose:</p>
<div class="language-env codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-env codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">TS_AUTHKEY=tskey-auth-xxx...</span><br></div></code></pre></div></div>
<p>Then <code>ts-config/serve.json</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;TCP&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;443&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">&quot;HTTPS&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;Web&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;${TS_CERT_DOMAIN}:443&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;Handlers&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;/&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">&quot;Proxy&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;http://127.0.0.1:8080&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div>
<p><code>${TS_CERT_DOMAIN}</code> is substituted by the Tailscale container at runtime with the hostname it gets in your tailnet (e.g. <code>dashy.tail123abc.ts.net</code>).</p>
<p>Bring it up:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">docker compose up -d</span><br></div></code></pre></div></div>
<p>The first run takes ~30 seconds while Tailscale joins the tailnet and provisions an HTTPS cert. After that, your tailnet name shows up in the admin console under <strong>Machines</strong>, and the URL becomes reachable from any device on the tailnet.</p>
<p>Notice what&#x27;s not in the compose: Dashy has no <code>ports:</code> mapping. It&#x27;s only reachable through Tailscale, never directly.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="configure-dashy">Configure Dashy<a href="#configure-dashy" class="hash-link" aria-label="Direct link to Configure Dashy" title="Direct link to Configure Dashy" translate="no"></a></h2>
<p>In <code>/user-data/conf.yml</code>:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">appConfig</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">disableConfigurationForNonAdmin</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">auth</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">enableHeaderAuth</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">users</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token key atrule">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> alice@example.com</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">hash</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;0000000000000000000000000000000000000000000000000000000000000000&quot;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">type</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> admin</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token key atrule">user</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> bob@example.com</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">hash</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;0000000000000000000000000000000000000000000000000000000000000000&quot;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">type</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> normal</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">headerAuth</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">userHeader</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Tailscale</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">User</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">Login</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token key atrule">proxyWhitelist</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> 127.0.0.1</span><br></div></code></pre></div></div>
<p>Where:</p>
<ul>
<li class=""><code>enableHeaderAuth</code> - Turns on header auth mode</li>
<li class=""><code>users</code> - The email Tailscale sends in <code>Tailscale-User-Login</code> must match <code>user</code> here. <code>type</code> controls admin status in Dashy</li>
<li class=""><code>hash</code> - Required by Dashy&#x27;s user schema even though the password is never checked under header auth. Quote it so YAML doesn&#x27;t parse an all-zero placeholder as the number 0</li>
<li class=""><code>userHeader</code> - The header <code>tailscale serve</code> sets on every proxied request, containing the tailnet user&#x27;s login (typically email)</li>
<li class=""><code>proxyWhitelist</code> - Just <code>127.0.0.1</code> because <code>tailscaled</code> and Dashy share a network namespace, so requests appear to come from localhost</li>
</ul>
<p>Restart Dashy after editing.</p>
<p>Open <code>https://dashy.&lt;your-tailnet&gt;.ts.net</code> from any device on your tailnet. You&#x27;ll land on the dashboard with the right admin level for your email. No login prompt.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="funnel-for-public-access-optional">Funnel for public access (optional)<a href="#funnel-for-public-access-optional" class="hash-link" aria-label="Direct link to Funnel for public access (optional)" title="Direct link to Funnel for public access (optional)" translate="no"></a></h2>
<p><a href="https://tailscale.com/kb/1223/funnel" target="_blank" rel="noopener noreferrer" class="">Tailscale Funnel</a> exposes a tailnet service to the public internet through Tailscale&#x27;s edge. It uses the same daemon and config, you just flip a switch in <code>serve.json</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;TCP&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;443&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">&quot;HTTPS&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;Web&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;${TS_CERT_DOMAIN}:443&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;Handlers&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;/&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">&quot;Proxy&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;http://127.0.0.1:8080&quot;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;AllowFunnel&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token property">&quot;${TS_CERT_DOMAIN}:443&quot;</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div>
<p>You also need to enable Funnel under <strong>Settings &gt; Funnel</strong> in the admin console and add your node to the allow-list.</p>
<p><strong>Important caveat on auth:</strong> Funnel requests come from the public internet, where the caller isn&#x27;t a tailnet member. Tailscale doesn&#x27;t inject identity headers on Funnel traffic, only on Serve traffic from authenticated tailnet peers. Header auth in Dashy would 401 every public visitor.</p>
<p>For a publicly-exposed Dashy via Funnel, you have two options:</p>
<ul>
<li class="">Use Dashy&#x27;s <a class="" href="/docs/authentication#http-auth">built-in HTTP auth</a> (<code>ENABLE_HTTP_AUTH=true</code> with users in <code>conf.yml</code>) so the browser prompts for credentials</li>
<li class="">Front Funnel with another auth layer, or just don&#x27;t expose via Funnel and stick to Serve plus the Tailscale apps on the user&#x27;s devices</li>
</ul>
<p>For a &quot;Funnel only allows my tailnet users in, but they show up as authenticated&quot; effect, use Serve, not Funnel. Funnel is for &quot;I want anyone on the internet to reach this&quot;.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-headscale-instead">Using Headscale instead<a href="#using-headscale-instead" class="hash-link" aria-label="Direct link to Using Headscale instead" title="Direct link to Using Headscale instead" translate="no"></a></h2>
<p><a href="https://github.com/juanfont/headscale" target="_blank" rel="noopener noreferrer" class="">Headscale</a> is a self-hosted reimplementation of Tailscale&#x27;s coordination server, compatible with the official Tailscale clients. Run your own and you don&#x27;t depend on Tailscale&#x27;s cloud for control-plane traffic.</p>
<p>For Dashy, everything in this guide applies unchanged. The only differences are:</p>
<ul>
<li class="">Point the <code>tailscaled</code> daemon at your Headscale server via the <code>TS_EXTRA_ARGS</code> env var:
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">TS_EXTRA_ARGS</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">login</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">server=https</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">//headscale.example.com </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">advertise</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">tags=tag</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">container</span><br></div></code></pre></div></div>
</li>
<li class="">Generate auth keys on the Headscale server (<code>headscale preauthkeys create --user &lt;user&gt;</code>) instead of the Tailscale admin console</li>
<li class="">ACLs are defined in Headscale&#x27;s policy file rather than the Tailscale admin UI</li>
<li class="">MagicDNS HTTPS certificates require Headscale ≥0.23. Older versions don&#x27;t auto-provision certs, so you&#x27;d need to terminate TLS yourself with a reverse proxy. Funnel is also Headscale ≥0.23</li>
</ul>
<p>The <code>serve.json</code> shape, the Dashy header-auth config, and the identity headers (<code>Tailscale-User-Login</code> etc.) are identical. Headscale uses the same protocol, so the client behaves the same way.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="best-practices">Best practices<a href="#best-practices" class="hash-link" aria-label="Direct link to Best practices" title="Direct link to Best practices" translate="no"></a></h2>
<ul>
<li class="">Don&#x27;t bind Dashy&#x27;s port to the host. Only <code>tailscaled</code> should reach it, which is the case if you leave <code>ports:</code> off the dashy service and use <code>network_mode: service:tailscale</code></li>
<li class="">Treat the auth key as a credential. Tag it (<code>tag:container</code>) and rotate it periodically. Prefer non-ephemeral keys for the Dashy node so it survives restarts</li>
<li class="">Use Tailscale ACLs to limit who in your tailnet can reach the Dashy node, especially for shared organisations. Configure under <strong>Access controls</strong> in the admin console</li>
<li class="">Pin <code>tailscale/tailscale</code> to a version tag in production rather than <code>:latest</code>. The Docker image follows the daemon&#x27;s release cadence</li>
<li class="">Match Dashy&#x27;s <code>users[]</code> to actual tailnet emails. Every tailnet member who should reach Dashy needs an entry. Promote to admin by setting <code>type: admin</code></li>
<li class="">For self-hosting purists, Headscale removes the dependency on Tailscale&#x27;s coordination server. Otherwise prefer the hosted plan, the free tier is generous and the engineering team owns reliability for you</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="troubleshooting-common-tailscale-issues">Troubleshooting common Tailscale issues<a href="#troubleshooting-common-tailscale-issues" class="hash-link" aria-label="Direct link to Troubleshooting common Tailscale issues" title="Direct link to Troubleshooting common Tailscale issues" translate="no"></a></h2>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="container-starts-but-no-machine-appears-in-the-tailscale-admin-console">Container starts but no machine appears in the Tailscale admin console<a href="#container-starts-but-no-machine-appears-in-the-tailscale-admin-console" class="hash-link" aria-label="Direct link to Container starts but no machine appears in the Tailscale admin console" title="Direct link to Container starts but no machine appears in the Tailscale admin console" translate="no"></a></h4>
<p>Problem: <code>docker compose logs tailscale</code> shows the daemon running but it never registers.<br>
Solution: The auth key is wrong, expired, or the wrong type. Generate a fresh <strong>Reusable: No, Ephemeral: No, Pre-approved: Yes</strong> key and update <code>.env</code>. Auth keys are single-use unless marked reusable.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="no-https-server-configured-for-ts_cert_domain">&quot;no HTTPS server configured for ${TS_CERT_DOMAIN}&quot;<a href="#no-https-server-configured-for-ts_cert_domain" class="hash-link" aria-label="Direct link to &quot;no HTTPS server configured for ${TS_CERT_DOMAIN}&quot;" title="Direct link to &quot;no HTTPS server configured for ${TS_CERT_DOMAIN}&quot;" translate="no"></a></h4>
<p>Problem: Serve config references the env-substituted hostname but Tailscale didn&#x27;t substitute it.<br>
Solution: Older <code>tailscale/tailscale</code> images didn&#x27;t expand <code>${TS_CERT_DOMAIN}</code> in <code>serve.json</code>. Update to a recent image (<code>v1.66+</code> or <code>latest</code>), or hardcode your tailnet hostname in <code>serve.json</code> (<code>dashy.tail123abc.ts.net:443</code>).</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="https-cert-never-issued">HTTPS cert never issued<a href="#https-cert-never-issued" class="hash-link" aria-label="Direct link to HTTPS cert never issued" title="Direct link to HTTPS cert never issued" translate="no"></a></h4>
<p>Problem: Browser shows a TLS error visiting the tailnet URL.<br>
Solution: HTTPS certificates aren&#x27;t enabled for your tailnet. Open <strong>DNS</strong> in the admin console and turn on both <strong>MagicDNS</strong> and <strong>HTTPS Certificates</strong>. Cert issuance takes about a minute after <code>serve.json</code> is applied.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="401-unauthorized---not-from-trusted-proxy-from-dashy">&quot;401 Unauthorized - not from trusted proxy&quot; from Dashy<a href="#401-unauthorized---not-from-trusted-proxy-from-dashy" class="hash-link" aria-label="Direct link to &quot;401 Unauthorized - not from trusted proxy&quot; from Dashy" title="Direct link to &quot;401 Unauthorized - not from trusted proxy&quot; from Dashy" translate="no"></a></h4>
<p>Problem: Reaches Dashy but the header auth middleware rejects it.<br>
Solution: <code>tailscaled</code> and Dashy must share a network namespace via <code>network_mode: service:tailscale</code> for the source IP to be <code>127.0.0.1</code>. If they&#x27;re on different networks, the source IP will be the Tailscale container&#x27;s IP instead. Update <code>proxyWhitelist</code> accordingly, or fix the compose to share the namespace.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="401-unauthorized---missing-user-header">&quot;401 Unauthorized - missing user header&quot;<a href="#401-unauthorized---missing-user-header" class="hash-link" aria-label="Direct link to &quot;401 Unauthorized - missing user header&quot;" title="Direct link to &quot;401 Unauthorized - missing user header&quot;" translate="no"></a></h4>
<p>Problem: Source IP check passes, but <code>Tailscale-User-Login</code> isn&#x27;t present.<br>
Solution: The request didn&#x27;t come through <code>tailscale serve</code> (maybe Funnel, maybe a direct hit on the tailnet IP without going via Serve). Confirm <code>serve.json</code> is loaded by running <code>docker compose exec tailscale tailscale serve status</code> and re-issuing the request through the HTTPS URL.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="logged-in-but-admin-features-stay-locked">Logged in but admin features stay locked<a href="#logged-in-but-admin-features-stay-locked" class="hash-link" aria-label="Direct link to Logged in but admin features stay locked" title="Direct link to Logged in but admin features stay locked" translate="no"></a></h4>
<p>Problem: Authenticates fine, but admin actions return 403.<br>
Solution: The email in <code>Tailscale-User-Login</code> doesn&#x27;t exactly match a <code>users[].user</code> with <code>type: admin</code>. Run <code>docker compose exec tailscale tailscale whois &lt;your-tailnet-ip&gt;</code> to see what login Tailscale will pass through.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="funnel-users-see-401">Funnel users see 401<a href="#funnel-users-see-401" class="hash-link" aria-label="Direct link to Funnel users see 401" title="Direct link to Funnel users see 401" translate="no"></a></h4>
<p>Problem: You enabled <code>AllowFunnel</code>, but visitors from outside the tailnet get 401.<br>
Solution: Expected. Funnel traffic doesn&#x27;t carry tailnet identity, so header auth has nothing to match. Either drop header auth and use built-in HTTP auth for Funnel-exposed Dashy, or only use Funnel for fully-public read access (no auth, guest mode).</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="tailscale-container-exits-with-cannot-allocate-memory-or-device_reset">Tailscale container exits with &quot;cannot allocate memory&quot; or DEVICE_RESET<a href="#tailscale-container-exits-with-cannot-allocate-memory-or-device_reset" class="hash-link" aria-label="Direct link to Tailscale container exits with &quot;cannot allocate memory&quot; or DEVICE_RESET" title="Direct link to Tailscale container exits with &quot;cannot allocate memory&quot; or DEVICE_RESET" translate="no"></a></h4>
<p>Problem: Crash loop on a low-memory host.<br>
Solution: Either bump memory, or set <code>TS_USERSPACE: &quot;true&quot;</code> to use the userspace WireGuard implementation (slower but no kernel module dependency). Remove the <code>/dev/net/tun</code> volume mount and the <code>net_admin</code> and <code>sys_module</code> capabilities when in userspace mode.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="magicdns-hostname-doesnt-resolve-from-the-device-im-using">MagicDNS hostname doesn&#x27;t resolve from the device I&#x27;m using<a href="#magicdns-hostname-doesnt-resolve-from-the-device-im-using" class="hash-link" aria-label="Direct link to MagicDNS hostname doesn&#x27;t resolve from the device I&#x27;m using" title="Direct link to MagicDNS hostname doesn&#x27;t resolve from the device I&#x27;m using" translate="no"></a></h4>
<p>Problem: Other tailnet devices can&#x27;t reach the Dashy URL even though the machine shows up in the admin console.<br>
Solution: Confirm MagicDNS is on globally (admin console <strong>DNS</strong>) and on the client (<code>tailscale netcheck</code> and the Tailscale app&#x27;s settings). On Linux clients add <code>--accept-dns=true</code> to <code>tailscale up</code>. Older Linux setups sometimes need <code>nameserver 100.100.100.100</code> in <code>/etc/resolv.conf</code>.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="headscale-setup-certs-not-issued-automatically">Headscale setup, certs not issued automatically<a href="#headscale-setup-certs-not-issued-automatically" class="hash-link" aria-label="Direct link to Headscale setup, certs not issued automatically" title="Direct link to Headscale setup, certs not issued automatically" translate="no"></a></h4>
<p>Problem: Using Headscale, the tailnet hostname works but HTTPS isn&#x27;t auto-provisioned.<br>
Solution: Headscale&#x27;s auto-cert support requires version 0.23 or newer. Either upgrade Headscale, or run your own reverse proxy with HTTPS (Caddy, Traefik) in front of the Tailscale daemon and route to it as you would any other internal service.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="config-change-to-authheaderauth-not-picked-up">Config change to auth.headerAuth not picked up<a href="#config-change-to-authheaderauth-not-picked-up" class="hash-link" aria-label="Direct link to Config change to auth.headerAuth not picked up" title="Direct link to Config change to auth.headerAuth not picked up" translate="no"></a></h4>
<p>Problem: Updated <code>userHeader</code>, <code>proxyWhitelist</code>, or <code>users</code> in <code>conf.yml</code>, but Dashy still uses the old values.<br>
Solution: The server reads the auth config only at boot. Restart the Dashy container after any change.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How it Works<a href="#how-it-works" class="hash-link" aria-label="Direct link to How it Works" title="Direct link to How it Works" translate="no"></a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="server-side">Server side<a href="#server-side" class="hash-link" aria-label="Direct link to Server side" title="Direct link to Server side" translate="no"></a></h3>
<p><code>tailscaled</code> runs WireGuard for the data plane and a small HTTPS server in the same container for Tailscale Serve. When a tailnet peer hits <code>https://dashy.&lt;tailnet&gt;.ts.net</code>, the request is delivered over WireGuard directly to your host. <code>tailscaled</code> terminates TLS using the cert it auto-provisioned, then makes an internal HTTP request to <code>http://127.0.0.1:8080</code> (Dashy in the same namespace), adding three headers:</p>
<ul>
<li class=""><code>Tailscale-User-Login</code> - the user&#x27;s tailnet login, typically their email</li>
<li class=""><code>Tailscale-User-Name</code> - the display name</li>
<li class=""><code>Tailscale-User-Profile-Pic</code> - a URL to their avatar</li>
</ul>
<p>Dashy&#x27;s <a href="https://github.com/lissy93/dashy/blob/4.1.5/services/app.js" target="_blank" rel="noopener noreferrer" class="">header auth middleware</a> checks <code>req.socket.remoteAddress</code> against <code>proxyWhitelist</code> (which is <code>127.0.0.1</code> because of the shared namespace), reads <code>Tailscale-User-Login</code>, and sets <code>req.auth = { user: &lt;email&gt; }</code>. The SPA&#x27;s <code>HeaderAuth.js</code> then fetches <code>/get-user</code>, matches the email to <code>users[]</code>, and sets the session cookie. Same code path as the Cloudflare Tunnel guide, just a different proxy and a different header name.</p>
<p>Identity flows from the user&#x27;s tailnet membership all the way to Dashy&#x27;s role-based UI without the user ever entering a password.</p>
<!-- -->
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>End-to-end authentication flow</summary><div><div class="collapsibleContent_i85q">
<!-- -->
<!-- -->
</div></div></details></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="row margin-top--sm theme-doc-footer-edit-meta-row"><div class="col noPrint_WFHX"><a href="https://github.com/Lissy93/dashy/edit/master/docs/docs/authentication/tailscale.md" target="_blank" rel="noopener noreferrer" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_JAkA"><span class="theme-last-updated">Last updated<!-- --> on <b><time datetime="2026-07-04T17:12:29.000Z" itemprop="dateModified">Jul 4, 2026</time></b></span></div></div></footer></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/docs/authentication/pocketid"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Pocket ID OIDC</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/docs/authentication/zitadel"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Zitadel OIDC</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#contents" class="table-of-contents__link toc-highlight">Contents</a></li><li><a href="#how-it-fits-together" class="table-of-contents__link toc-highlight">How it fits together</a></li><li><a href="#prepare-tailscale" class="table-of-contents__link toc-highlight">Prepare Tailscale</a></li><li><a href="#run-tailscale--dashy-together" class="table-of-contents__link toc-highlight">Run Tailscale + Dashy together</a></li><li><a href="#configure-dashy" class="table-of-contents__link toc-highlight">Configure Dashy</a></li><li><a href="#funnel-for-public-access-optional" class="table-of-contents__link toc-highlight">Funnel for public access (optional)</a></li><li><a href="#using-headscale-instead" class="table-of-contents__link toc-highlight">Using Headscale instead</a></li><li><a href="#best-practices" class="table-of-contents__link toc-highlight">Best practices</a></li><li><a href="#troubleshooting-common-tailscale-issues" class="table-of-contents__link toc-highlight">Troubleshooting common Tailscale issues</a></li><li><a href="#how-it-works" class="table-of-contents__link toc-highlight">How it Works</a><ul><li><a href="#server-side" class="table-of-contents__link toc-highlight">Server side</a></li></ul></li></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Intro</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://github.com/lissy93/dashy" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://demo.dashy.to" target="_blank" rel="noopener noreferrer" class="footer__link-item">Live Demo<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a class="footer__link-item" href="/docs/quick-start">Quick Start</a></li><li class="footer__item"><a class="footer__link-item" href="/docs">Documentation</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Setup Guide</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/deployment">Deploying</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/configuring">Configuring</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/management">Management</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/troubleshooting">Troubleshooting</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Feature Docs Pt 1</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/authentication">Authentication</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/alternate-views">Alternate Views</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/backup-restore">Backup &amp; Restore</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/icons">Icons</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Feature Docs Pt 2</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/multi-language-support">Language Switching</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/status-indicators">Status Indicators</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/searching">Searching &amp; Shortcuts</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/theming">Theming</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/developing">Developing</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/development-guides">Development Guides</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/contributing">Contributing</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/showcase">Showcase</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/credits">Credits</a></li></ul></div><div class="theme-layout-footer-column col footer__col"><div class="footer__title">Misc</div><ul class="footer__items clean-list"><li class="footer__item"><a class="footer__link-item" href="/docs/privacy">Privacy &amp; Security</a></li><li class="footer__item"><a class="footer__link-item" href="/docs/license">License</a></li><li class="footer__item"><a href="https://github.com/Lissy93/dashy/blob/master/.github/LEGAL.md" target="_blank" rel="noopener noreferrer" class="footer__link-item">Legal<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://github.com/Lissy93/dashy/blob/master/.github/CODE_OF_CONDUCT.md" target="_blank" rel="noopener noreferrer" class="footer__link-item">Code of Conduct<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li><li class="footer__item"><a href="https://github.com/Lissy93/dashy/blob/master/.github/CHANGELOG.md" target="_blank" rel="noopener noreferrer" class="footer__link-item">Changelog<svg width="13.5" height="13.5" aria-label="(opens in new tab)" class="iconExternalLink_nPIU"><use href="#theme-svg-external-link"></use></svg></a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright"><a href="https://dashy.to">Dashy</a> - The Self-Hosted Dashboard for your Homelab<br>License under <a href="https://github.com/Lissy93/dashy/blob/master/LICENSE">MIT</a>. Copyright © 2026 <a href="https://aliciasykes.com">Alicia Sykes</a></div></div></div></footer></div>
</body>
</html>