<!doctype html><htmllang=enclass=no-js><head><metacharset=utf-8><metaname=viewportcontent="width=device-width,initial-scale=1"><metaname=descriptioncontent="An open source, self-hosted implementation of the Tailscale control server."><metaname=authorcontent="Headscale authors"><linkhref=https://juanfont.github.io/headscale/development/ref/derp/rel=canonical><linkhref=../dns/rel=prev><linkhref=../remote-cli/rel=next><linkrel=iconhref=../../assets/favicon.png><metaname=generatorcontent="mkdocs-1.6.1, mkdocs-material-9.6.22"><title>DERP - Headscale</title><linkrel=stylesheethref=../../assets/stylesheets/main.84d31ad4.min.css><linkrel=stylesheethref=../../assets/stylesheets/palette.06af60db.min.css><linkrel=preconnecthref=https://fonts.gstatic.comcrossorigin><linkrel=stylesheethref="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback"><style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style><script>__md_scope=newURL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script><metaproperty=og:typecontent=website><metaproperty=og:titlecontent="DERP - Headscale"><metaproperty=og:descriptioncontent="An open source, self-hosted implementation of the Tailscale control server."><metaproperty=og:imagecontent=https://juanfont.github.io/headscale/development/assets/images/social/ref/derp.png><metaproperty=og:image:typecontent=image/png><metaproperty=og:image:widthcontent=1200><metaproperty=og:image:heightcontent=630><metacontent=https://juanfont.github.io/headscale/development/ref/derp/property=og:url><metaname=twitter:cardcontent=summary_large_image><metaname=twitter:titlecontent="DERP - Headscale"><metaname=twitter:descriptioncontent="An open source, self-hosted implementation of the Tailscale control server."><metaname=twitter:imagecontent=https://juanfont.github.io/headscale/development/assets/images/social/ref/derp.png></head><bodydir=ltrdata-md-color-scheme=defaultdata-md-color-primary=whitedata-md-color-accent=indigo><inputclass=md-toggledata-md-toggle=drawertype=checkboxid=__drawerautocomplete=off><inputclass=md-toggledata-md-toggle=searchtype=checkboxid=__searchautocomplete=off><labelclass=md-overlayfor=__drawer></label><divdata-md-component=skip><ahref=#derpclass=md-skip> Skip to content </a></div><divdata-md-component=announce></div><divdata-md-color-scheme=defaultdata-md-component=outdatedhidden></div><headerclass=md-headerdata-md-component=header><navclass="md-header__inner md-grid"aria-label=Header><ahref=../..title=Headscaleclass="md-header__button md-logo"aria-label=Headscaledata-md-component=logo><imgsrc=../../logo/headscale3-dots.svgalt=logo></a><labelclass="md-header__button md-icon"for=__drawer><svgxmlns=http://www.w3.org/2000/svgviewbox="0 0 24 24"><pathd="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg></label><divclass=md-header__titledata-md-component=header-title><divclass=md-header__ellipsis><divclass=md-header__topic><spanclass=md-ellipsis> Headscale </span></div><divclass=md-header__topicdata-md-component=header-topic><spanclass=md-ellipsis> DERP </span></div></div></div><formclass=md-header__optiondata-md-component=palette><inputclass=md-optiondata-md-color-mediadata-md-color-scheme=defaultdata-md-color-primary=whitedata-md-color-accent=indigoaria-label="Switch to dark mode"type=radioname=__paletteid=__palette_0><labelclass="md-header__button md-icon"title="Switch to dark mode"for=__palette_1hidden><svgxmlns=http://www.w3.org/2000/svgviewbox="0 0 24 24"><pathd="M128a44000-444400044440004-444000-4-4m010a66001-6-6660016-6660016666001-66m8-9.31V4h-4.69L12.698.694H4v4.69L.6912415.31V20h4.69L1223.3115.3120H
</span></span></code></pre></div><p>Keep in mind that <ahref=../../setup/requirements/#ports-in-use>additional ports are needed to run a DERP server</a>. Besides relaying traffic, it also uses STUN (udp/3478) to help clients discover their public IP addresses and perform NAT traversal. <ahref=#check-derp-server-connectivity>Check DERP server connectivity</a> to see if everything works.</p><h3id=remove-tailscales-derp-servers>Remove Tailscale's DERP servers<aclass=headerlinkhref=#remove-tailscales-derp-serverstitle="Permanent link">¶</a></h3><p>Once enabled, Headscale's embedded DERP is added to the list of free-to-use <ahref=https://tailscale.com/kb/1232/derp-servers>DERP servers</a> offered by Tailscale Inc. To only use Headscale's embedded DERP server, disable the loading of the default DERP map:</p><divclass="language-yaml highlight"><spanclass=filename>config.yaml</span><pre><span></span><code><spanid=__span-1-1><aid=__codelineno-1-1name=__codelineno-1-1href=#__codelineno-1-1></a><spanclass=nt>derp</span><spanclass=p>:</span>
</span></span></code></pre></div><divclass="admonition warning"><pclass=admonition-title>Single point of failure</p><p>Removing Tailscale's DERP servers means that there is now just a single DERP server available for clients. This is a single point of failure and could hamper connectivity.</p><p><ahref=#check-derp-server-connectivity>Check DERP server connectivity</a> with your embedded DERP server before removing Tailscale's DERP servers.</p></div><h3id=customize-derp-map>Customize DERP map<aclass=headerlinkhref=#customize-derp-maptitle="Permanent link">¶</a></h3><p>The DERP map offered to clients can be customized with a <ahref=https://github.com/juanfont/headscale/blob/main/derp-example.yaml>dedicated YAML-configuration file</a>. This allows to modify previously loaded DERP maps fetched via URL or to offer your own, custom DERP servers to nodes.</p><divclass="tabbed-set tabbed-alternate"data-tabs=1:2><inputchecked=checkedid=__tabbed_1_1name=__tabbed_1type=radio><inputid=__tabbed_1_2name=__tabbed_1type=radio><divclass=tabbed-labels><labelfor=__tabbed_1_1>Remove specific DERP regions</label><labelfor=__tabbed_1_2>Provide custom DERP servers</label></div><divclass=tabbed-content><divclass=tabbed-block><p>The free-to-use <ahref=https://tailscale.com/kb/1232/derp-servers>DERP servers</a> are organized into regions via a region ID. You can explicitly disable a specific region by setting its region ID to <code>null</code>. The following sample <code>derp.yaml</code> disables the New York DERP region (which has the region ID 1):</p><divclass="language-yaml highlight"><spanclass=filename>derp.yaml</span><pre><span></span><code><spanid=__span-2-1><aid=__codelineno-2-1name=__codelineno-2-1href=#__codelineno-2-1></a><spanclass=nt>regions</span><spanclass=p>:</span>
</span></code></pre></div><p>Use the following configuration to serve the default DERP map (excluding New York) to nodes:</p><divclass="language-yaml highlight"><spanclass=filename>config.yaml</span><pre><span></span><code><spanid=__span-3-1><aid=__codelineno-3-1name=__codelineno-3-1href=#__codelineno-3-1></a><spanclass=nt>derp</span><spanclass=p>:</span>
</span></span></code></pre></div></div><divclass=tabbed-block><p>The following sample <code>derp.yaml</code> references two custom regions (<code>custom-east</code> with ID 900 and <code>custom-west</code> with ID 901) with one custom DERP server in each region. Each DERP server offers DERP relay via HTTPS on tcp/443, support for captive portal checks via HTTP on tcp/80 and STUN on udp/3478. See the definitions of <ahref=https://pkg.go.dev/tailscale.com/tailcfg#DERPMap>DERPMap</a>, <ahref=https://pkg.go.dev/tailscale.com/tailcfg#DERPRegion>DERPRegion</a> and <ahref=https://pkg.go.dev/tailscale.com/tailcfg#DERPNode>DERPNode</a> for all available options.</p><divclass="language-yaml highlight"><spanclass=filename>derp.yaml</span><pre><span></span><code><spanid=__span-4-1><aid=__codelineno-4-1name=__codelineno-4-1href=#__codelineno-4-1></a><spanclass=nt>regions</span><spanclass=p>:</span>
</span><spanid=__span-4-5><aid=__codelineno-4-5name=__codelineno-4-5href=#__codelineno-4-5></a><spanclass=w></span><spanclass=nt>regionname</span><spanclass=p>:</span><spanclass=w></span><spanclass="l l-Scalar l-Scalar-Plain">My region (east)</span>
</span><spanid=__span-4-16><aid=__codelineno-4-16name=__codelineno-4-16href=#__codelineno-4-16></a><spanclass=w></span><spanclass=nt>regionname</span><spanclass=p>:</span><spanclass=w></span><spanclass="l l-Scalar l-Scalar-Plain">My Region (west)</span>
</span></code></pre></div><p>Use the following configuration to only serve the two DERP servers from the above <code>derp.yaml</code>:</p><divclass="language-yaml highlight"><spanclass=filename>config.yaml</span><pre><span></span><code><spanid=__span-5-1><aid=__codelineno-5-1name=__codelineno-5-1href=#__codelineno-5-1></a><spanclass=nt>derp</span><spanclass=p>:</span>
</span></span></code></pre></div></div></div></div><p>Independent of the custom DERP map, you may choose to <ahref=#enable-embedded-derp>enable the embedded DERP server and have it automatically added to the custom DERP map</a>.</p><h3id=verify-clients>Verify clients<aclass=headerlinkhref=#verify-clientstitle="Permanent link">¶</a></h3><p>Access to DERP serves can be restricted to nodes that are members of your Tailnet. Relay access is denied for unknown clients.</p><divclass="tabbed-set tabbed-alternate"data-tabs=2:2><inputchecked=checkedid=__tabbed_2_1name=__tabbed_2type=radio><inputid=__tabbed_2_2name=__tabbed_2type=radio><divclass=tabbed-labels><labelfor=__tabbed_2_1>Embedded DERP</label><labelfor=__tabbed_2_2>3<sup>rd</sup>-party DERP</label></div><divclass=tabbed-content><divclass=tabbed-block><p>Client verification is enabled by default.</p><divclass="language-yaml highlight"><spanclass=filename>config.yaml</span><pre><span></span><code><spanid=__span-6-1><aid=__codelineno-6-1name=__codelineno-6-1href=#__codelineno-6-1></a><spanclass=nt>derp</span><spanclass=p>:</span>