Skip to main content

Merge pull request #16 from alexwlchan/remove-nitrate

ID
32c86b3
date
2026-03-28 13:15:37+00:00
author
Alex Chan <alex@alexwlchan.net>
parents
7b43a22, 7fd9cd0
message
Merge pull request #16 from alexwlchan/remove-nitrate

Remove dependencies on silver-nitrate and https
changed files
15 files, 1187 additions, 231 deletions

Changed files

dev_requirements.in (100) → dev_requirements.in (85)

diff --git a/dev_requirements.in b/dev_requirements.in
index 730f3d7..735adba 100644
--- a/dev_requirements.in
+++ b/dev_requirements.in
@@ -3,6 +3,6 @@
 build
 mypy
 pytest-cov
+pytest-vcr
 ruff
-silver-nitrate[cassettes]
 twine

dev_requirements.txt (2477) → dev_requirements.txt (2259)

diff --git a/dev_requirements.txt b/dev_requirements.txt
index 2683edd..1e90bc9 100644
--- a/dev_requirements.txt
+++ b/dev_requirements.txt
@@ -1,45 +1,34 @@
 # This file was autogenerated by uv via the following command:
-#    uv pip compile dev_requirements.in --output-file dev_requirements.txt
+#    uv pip compile dev_requirements.in --output-file=dev_requirements.txt --exclude-newer=P7D
 -e file:.
     # via -r dev_requirements.in
-anyio==4.12.1
-    # via httpx
 build==1.4.0
     # via -r dev_requirements.in
 certifi==2026.2.25
     # via
-    #   httpcore
-    #   httpx
+    #   alexwlchan-chives
     #   requests
-charset-normalizer==3.4.4
+charset-normalizer==3.4.6
     # via requests
-coverage==7.13.4
+coverage==7.13.5
     # via pytest-cov
 docutils==0.22.4
     # via readme-renderer
 greenlet==3.3.2
     # via playwright
-h11==0.16.0
-    # via httpcore
-httpcore==1.0.9
-    # via httpx
-httpx==0.28.1
-    # via alexwlchan-chives
 hyperlink==21.0.0
     # via alexwlchan-chives
 id==1.6.1
     # via twine
 idna==3.11
     # via
-    #   anyio
-    #   httpx
     #   hyperlink
     #   requests
 iniconfig==2.3.0
     # via pytest
 jaraco-classes==3.4.0
     # via keyring
-jaraco-context==6.1.0
+jaraco-context==6.1.1
     # via keyring
 jaraco-functools==4.4.0
     # via keyring
@@ -90,11 +79,10 @@ pytest==9.0.2
     #   alexwlchan-chives
     #   pytest-cov
     #   pytest-vcr
-    #   silver-nitrate
 pytest-cov==7.0.0
     # via -r dev_requirements.in
 pytest-vcr==1.0.2
-    # via silver-nitrate
+    # via -r dev_requirements.in
 pyyaml==6.0.3
     # via vcrpy
 rapidfuzz==3.14.3
@@ -111,9 +99,7 @@ rfc3986==2.0.0
     # via twine
 rich==14.3.3
     # via twine
-ruff==0.15.4
-    # via -r dev_requirements.in
-silver-nitrate==1.8.1
+ruff==0.15.7
     # via -r dev_requirements.in
 twine==6.2.0
     # via -r dev_requirements.in
@@ -128,5 +114,5 @@ urllib3==2.6.3
     #   twine
 vcrpy==8.1.1
     # via pytest-vcr
-wrapt==2.1.1
+wrapt==2.1.2
     # via vcrpy

pyproject.toml (1350) → pyproject.toml (1297)

diff --git a/pyproject.toml b/pyproject.toml
index 45ef880..355cb94 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,7 +26,7 @@ license = "MIT"
 [project.optional-dependencies]
 media = ["Pillow"]
 static_site_tests = ["playwright", "pytest", "rapidfuzz"]
-urls = ["httpx", "hyperlink"]
+urls = ["certifi", "hyperlink"]
 
 [project.urls]
 "Homepage" = "https://github.com/alexwlchan/chives"
@@ -38,9 +38,6 @@ version = {attr = "chives.__version__"}
 [tool.setuptools.packages.find]
 where = ["src"]
 
-[tool.setuptools.package-data]
-nitrate = ["py.typed"]
-
 [tool.coverage.run]
 branch = true
 source = ["chives", "tests",]

src/chives/urls.py (3526) → src/chives/urls.py (3908)

diff --git a/src/chives/urls.py b/src/chives/urls.py
index cb6021a..ecdec90 100644
--- a/src/chives/urls.py
+++ b/src/chives/urls.py
@@ -1,7 +1,15 @@
 """Code for manipulating and tidying URLs."""
 
+import json
 from pathlib import Path
 import re
+import ssl
+from ssl import SSLCertVerificationError
+import urllib.error
+from urllib.error import HTTPError
+import urllib.request
+
+import certifi
 
 
 __all__ = [
@@ -43,6 +51,8 @@ def is_mastodon_host(hostname: str) -> bool:
     }:
         return True
 
+    ssl_context = ssl.create_default_context(cafile=certifi.where())
+
     # See https://github.com/mastodon/mastodon/discussions/30547
     #
     # Fist we look at /.well-known/nodeinfo, which returns a response
@@ -57,14 +67,19 @@ def is_mastodon_host(hostname: str) -> bool:
     #       ]
     #     }
     #
-    import httpx
+    nodeinfo_url = f"https://{hostname}/.well-known/nodeinfo"
 
-    nodeinfo_resp = httpx.get(f"https://{hostname}/.well-known/nodeinfo")
     try:
-        nodeinfo_resp.raise_for_status()
-    except Exception:
+        nodeinfo_resp = urllib.request.urlopen(nodeinfo_url, context=ssl_context)
+    except HTTPError as err:
+        err.close()
+        return False
+    except SSLCertVerificationError:
         return False
 
+    nodeinfo = json.loads(nodeinfo_resp.read())
+    nodeinfo_resp.close()
+
     # Then we try to call $.links[0].href, which should return something
     # like:
     #
@@ -74,18 +89,16 @@ def is_mastodon_host(hostname: str) -> bool:
     #       …
     #
     try:
-        href = nodeinfo_resp.json()["links"][0]["href"]
+        link_href = nodeinfo["links"][0]["href"]
     except (KeyError, IndexError):  # pragma: no cover
         return False
 
-    link_resp = httpx.get(href)
-    try:
-        link_resp.raise_for_status()
-    except Exception:  # pragma: no cover
-        return False
+    link_resp = urllib.request.urlopen(link_href, context=ssl_context)
+    link_info = json.loads(link_resp.read())
+    link_resp.close()
 
     try:
-        return bool(link_resp.json()["software"]["name"] == "mastodon")
+        return bool(link_info["software"]["name"] == "mastodon")
     except (KeyError, IndexError):  # pragma: no cover
         return False
 

tests/cassettes.py (0) → tests/cassettes.py (2213)

diff --git a/tests/cassettes.py b/tests/cassettes.py
new file mode 100644
index 0000000..b568dd8
--- /dev/null
+++ b/tests/cassettes.py
@@ -0,0 +1,77 @@
+"""
+pytest fixtures for working with vcrpy to record HTTP requests.
+
+This allows us to record HTTP interactions as YAML files, so they can
+be "played back" later -- e.g. in automated tests or GitHub Actions.
+This means our tests are working with real responses, but don't
+depend on the original service being up and running.
+
+This establishes a couple of conventions for where cassettes are stored
+and how they're named.
+
+See https://vcrpy.readthedocs.io/
+"""
+
+from collections.abc import Iterator
+
+import pytest
+import vcr
+from vcr.cassette import Cassette
+
+
+__all__ = ["cassette_name", "vcr_cassette"]
+
+
+def get_cassette_name(request: pytest.FixtureRequest) -> str:
+    """
+    Returns the name of a cassette for vcr.py.
+
+    The name can be made up of (up to) three parts:
+
+    -   the name of the test class
+    -   the name of the test function
+    -   the ID of the test case in @pytest.mark.parametrize
+
+    """
+    name = request.node.name
+
+    # This is to catch cases where e.g. we try to include a complete
+    # HTTP URL in a cassette name, which creates very messy folders in
+    # the fixtures directory.
+    if any(char in name for char in ":/"):
+        raise ValueError(
+            "Illegal characters in VCR cassette name - "
+            "please set a test ID with pytest.param(…, id='…')"
+        )
+
+    if request.cls is not None:
+        return f"{request.cls.__name__}.{name}.yml"
+    else:
+        return f"{name}.yml"
+
+
+@pytest.fixture
+def cassette_name(request: pytest.FixtureRequest) -> str:
+    """
+    Returns the filename of a VCR cassette to use in tests.
+
+    This is useful when you need some custom vcr.py options, and
+    can't use the prebuilt `vcr_cassette` fixture.
+    """
+    return get_cassette_name(request)
+
+
+@pytest.fixture
+def vcr_cassette(cassette_name: str) -> Iterator[Cassette]:
+    """
+    Creates a VCR cassette for use in tests.
+
+    Tests will record their HTTP interactions as "cassettes" using vcr.py,
+    which can be replayed offline (e.g. in CI tests).
+    """
+    with vcr.use_cassette(
+        cassette_name,
+        cassette_library_dir="tests/fixtures/cassettes",
+        decode_compressed_response=True,
+    ) as cassette:
+        yield cassette

tests/conftest.py (173) → tests/conftest.py (165)

diff --git a/tests/conftest.py b/tests/conftest.py
index 9a07b84..993aeab 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,6 +1,6 @@
 """Shared helpers and test fixtures."""
 
-from nitrate.cassettes import cassette_name, vcr_cassette
+from cassettes import cassette_name, vcr_cassette
 
 pytest_plugins = "pytester"
 

tests/fixtures/cassettes/TestIsMastodonHost.test_mastodon_servers[social.jvns.ca].yml (4230) → tests/fixtures/cassettes/TestIsMastodonHost.test_mastodon_servers[social.jvns.ca].yml (4418)

diff --git a/tests/fixtures/cassettes/TestIsMastodonHost.test_mastodon_servers[social.jvns.ca].yml b/tests/fixtures/cassettes/TestIsMastodonHost.test_mastodon_servers[social.jvns.ca].yml
index f240d7c..14ba026 100644
--- a/tests/fixtures/cassettes/TestIsMastodonHost.test_mastodon_servers[social.jvns.ca].yml
+++ b/tests/fixtures/cassettes/TestIsMastodonHost.test_mastodon_servers[social.jvns.ca].yml
@@ -1,17 +1,13 @@
 interactions:
 - request:
-    body: ''
+    body: null
     headers:
-      Accept:
-      - '*/*'
-      Accept-Encoding:
-      - gzip, deflate
       Connection:
-      - keep-alive
+      - close
       Host:
       - social.jvns.ca
       User-Agent:
-      - python-httpx/0.28.1
+      - Python-urllib/3.14
     method: GET
     uri: https://social.jvns.ca/.well-known/nodeinfo
   response:
@@ -19,19 +15,21 @@ interactions:
       string: '{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"https://social.jvns.ca/nodeinfo/2.0"}]}'
     headers:
       Connection:
-      - keep-alive
+      - close
+      Content-Length:
+      - '114'
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Thu, 04 Dec 2025 12:14:49 GMT
+      - Sat, 28 Mar 2026 11:28:19 GMT
       Strict-Transport-Security:
+      - max-age=63072000; includeSubDomains
       - max-age=31536000
-      Transfer-Encoding:
-      - chunked
+      Vary:
+      - Accept-Encoding
+      - Origin
       cache-control:
       - max-age=259200, public
-      content-length:
-      - '114'
       content-security-policy:
       - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
         ''self'' https://social.jvns.ca; img-src ''self'' data: blob: https://social.jvns.ca
@@ -40,61 +38,63 @@ interactions:
         ''self'' blob: https://social.jvns.ca; worker-src ''self'' blob: https://social.jvns.ca;
         connect-src ''self'' data: blob: https://social.jvns.ca https://cdn.masto.host
         wss://social.jvns.ca; script-src ''self'' https://social.jvns.ca ''wasm-unsafe-eval'';
-        frame-src ''self'' https:; style-src ''self'' https://social.jvns.ca ''nonce-cYXJpX/juTVw0Sc+MAA7BQ=='''
+        frame-src ''self'' https:; style-src ''self'' https://social.jvns.ca ''nonce-SLG/a2lOZjjg0yVI2h0UFQ=='''
       etag:
       - W/"41981c7ccfa1674c1535b6eea835d7e5"
       referrer-policy:
       - same-origin
       server:
       - Mastodon
+      strict-transport-security:
+      - max-age=63072000; includeSubDomains
+      - max-age=31536000
       vary:
+      - Accept-Encoding
       - Origin
       x-content-type-options:
       - nosniff
       x-frame-options:
       - DENY
       x-request-id:
-      - d4888141-9cb3-4305-b5dd-a8b0842a2d05
+      - 7492826e-5911-4ac8-bd7c-1ef18fb5a3c1
       x-runtime:
-      - '0.003398'
+      - '0.001392'
       x-xss-protection:
       - '0'
     status:
       code: 200
       message: OK
 - request:
-    body: ''
+    body: null
     headers:
-      Accept:
-      - '*/*'
-      Accept-Encoding:
-      - gzip, deflate
       Connection:
-      - keep-alive
+      - close
       Host:
       - social.jvns.ca
       User-Agent:
-      - python-httpx/0.28.1
+      - Python-urllib/3.14
     method: GET
     uri: https://social.jvns.ca/nodeinfo/2.0
   response:
     body:
-      string: '{"version":"2.0","software":{"name":"mastodon","version":"4.5.2"},"protocols":["activitypub"],"services":{"outbound":[],"inbound":[]},"usage":{"users":{"total":4,"activeMonth":4,"activeHalfyear":4},"localPosts":7409},"openRegistrations":false,"metadata":{"nodeName":"Mastodon","nodeDescription":""}}'
+      string: '{"version":"2.0","software":{"name":"mastodon","version":"4.5.8"},"protocols":["activitypub"],"services":{"outbound":[],"inbound":[]},"usage":{"users":{"total":4,"activeMonth":4,"activeHalfyear":4},"localPosts":7915},"openRegistrations":false,"metadata":{"nodeName":"Mastodon","nodeDescription":""}}'
     headers:
       Connection:
-      - keep-alive
+      - close
+      Content-Length:
+      - '299'
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Thu, 04 Dec 2025 12:14:49 GMT
+      - Sat, 28 Mar 2026 11:28:19 GMT
       Strict-Transport-Security:
+      - max-age=63072000; includeSubDomains
       - max-age=31536000
-      Transfer-Encoding:
-      - chunked
+      Vary:
+      - Accept-Encoding
+      - Origin
       cache-control:
       - max-age=1800, public
-      content-length:
-      - '299'
       content-security-policy:
       - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src
         ''self'' https://social.jvns.ca; img-src ''self'' data: blob: https://social.jvns.ca
@@ -103,23 +103,27 @@ interactions:
         ''self'' blob: https://social.jvns.ca; worker-src ''self'' blob: https://social.jvns.ca;
         connect-src ''self'' data: blob: https://social.jvns.ca https://cdn.masto.host
         wss://social.jvns.ca; script-src ''self'' https://social.jvns.ca ''wasm-unsafe-eval'';
-        frame-src ''self'' https:; style-src ''self'' https://social.jvns.ca ''nonce-KudwCpfFUyr8bIzc9hLCuA=='''
+        frame-src ''self'' https:; style-src ''self'' https://social.jvns.ca ''nonce-uvtrA197UKg93d3cEYFepw=='''
       etag:
-      - W/"def238b77fc5db88a115321ee60e49e7"
+      - W/"e5770b11e9504692808d5c4bbb2a1741"
       referrer-policy:
       - same-origin
       server:
       - Mastodon
+      strict-transport-security:
+      - max-age=63072000; includeSubDomains
+      - max-age=31536000
       vary:
-      - Accept, Origin
+      - Accept-Encoding
+      - Origin
       x-content-type-options:
       - nosniff
       x-frame-options:
       - DENY
       x-request-id:
-      - 3ef92cee-53b7-41e1-b1f1-5b9b094c5616
+      - 0161e669-c01b-4ad0-b976-78c6185f6157
       x-runtime:
-      - '0.008559'
+      - '0.001917'
       x-xss-protection:
       - '0'
     status:

tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[alexwlchan.net].yml (1406) → tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[alexwlchan.net].yml (0)

diff --git a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[alexwlchan.net].yml b/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[alexwlchan.net].yml
deleted file mode 100644
index 6b8e4c1..0000000
--- a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[alexwlchan.net].yml
+++ /dev/null
@@ -1,51 +0,0 @@
-interactions:
-- request:
-    body: ''
-    headers:
-      Accept:
-      - '*/*'
-      Accept-Encoding:
-      - gzip, deflate
-      Connection:
-      - keep-alive
-      Host:
-      - alexwlchan.net
-      User-Agent:
-      - python-httpx/0.28.1
-    method: GET
-    uri: https://alexwlchan.net/.well-known/nodeinfo
-  response:
-    body:
-      string: ''
-    headers:
-      Alt-Svc:
-      - h3=":443"; ma=2592000
-      Content-Length:
-      - '0'
-      Content-Security-Policy:
-      - 'default-src ''self'' ''unsafe-inline'' https://youtube-nocookie.com https://www.youtube-nocookie.com;
-        script-src ''self'' ''unsafe-inline''; connect-src https://analytics.alexwlchan.net;
-        img-src ''self'' ''unsafe-inline'' data:'
-      Date:
-      - Thu, 04 Dec 2025 12:15:34 GMT
-      Location:
-      - https://social.alexwlchan.net/.well-known/nodeinfo
-      Permissions-Policy:
-      - geolocation=(), midi=(), notifications=(), push=(), sync-xhr=(), microphone=(),
-        camera=(), magnetometer=(), gyroscope=(), vibrate=(), payment=()
-      Referrer-Policy:
-      - no-referrer-when-downgrade
-      Server:
-      - Caddy
-      Strict-Transport-Security:
-      - max-age=31536000; includeSubDomains
-      X-Content-Type-Options:
-      - nosniff
-      X-Frame-Options:
-      - ALLOWALL
-      X-Xss-Protection:
-      - 1; mode=block
-    status:
-      code: 301
-      message: Moved Permanently
-version: 1

tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[example.com].yml (1538) → tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[example.com].yml (0)

diff --git a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[example.com].yml b/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[example.com].yml
deleted file mode 100644
index 4a0f6f1..0000000
--- a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[example.com].yml
+++ /dev/null
@@ -1,55 +0,0 @@
-interactions:
-- request:
-    body: ''
-    headers:
-      Accept:
-      - '*/*'
-      Accept-Encoding:
-      - gzip, deflate
-      Connection:
-      - keep-alive
-      Host:
-      - example.com
-      User-Agent:
-      - python-httpx/0.28.1
-    method: GET
-    uri: https://example.com/.well-known/nodeinfo
-  response:
-    body:
-      string: '<!doctype html><html lang="en"><head><title>Example Domain</title><meta
-        name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh
-        auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example
-        Domain</h1><p>This domain is for use in documentation examples without needing
-        permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn
-        more</a></div></body></html>
-
-        '
-    headers:
-      Accept-Ranges:
-      - bytes
-      Alt-Svc:
-      - h3=":443"; ma=93600
-      Cache-Control:
-      - max-age=0, no-cache, no-store
-      Connection:
-      - keep-alive
-      Content-Length:
-      - '513'
-      Content-Type:
-      - text/html
-      Date:
-      - Thu, 04 Dec 2025 12:15:34 GMT
-      ETag:
-      - '"bc2473a18e003bdb249eba5ce893033f:1760028122.592274"'
-      Expires:
-      - Thu, 04 Dec 2025 12:15:34 GMT
-      Last-Modified:
-      - Thu, 09 Oct 2025 16:42:02 GMT
-      Pragma:
-      - no-cache
-      Server:
-      - AkamaiNetStorage
-    status:
-      code: 404
-      message: Not Found
-version: 1

tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[peertube.tv].yml (7608) → tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[peertube.tv].yml (5130)

diff --git a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[peertube.tv].yml b/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[peertube.tv].yml
index 75d1597..e1689b7 100644
--- a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[peertube.tv].yml
+++ b/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[peertube.tv].yml
@@ -1,102 +1,99 @@
 interactions:
 - request:
-    body: ''
+    body: null
     headers:
-      Accept:
-      - '*/*'
-      Accept-Encoding:
-      - gzip, deflate
       Connection:
-      - keep-alive
+      - close
       Host:
       - peertube.tv
       User-Agent:
-      - python-httpx/0.28.1
+      - Python-urllib/3.14
     method: GET
     uri: https://peertube.tv/.well-known/nodeinfo
   response:
     body:
-      string: '{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"https://peertube.tv/nodeinfo/2.0.json"}]}'
+      string: '{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"https://peertube.tv/nodeinfo/2.0.json"},{"rel":"https://www.w3.org/ns/activitystreams#Application","href":"https://peertube.tv/accounts/peertube"}]}'
     headers:
+      Access-Control-Allow-Origin:
+      - '*'
       Connection:
-      - keep-alive
+      - close
       Content-Length:
-      - '116'
+      - '223'
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Thu, 04 Dec 2025 12:17:46 GMT
+      - Sat, 28 Mar 2026 11:28:20 GMT
+      ETag:
+      - W/"df-TklFQ/9IV5DIROi4BSS0TgZ5/L4"
       Server:
-      - nginx/1.18.0 (Ubuntu)
-      access-control-allow-origin:
-      - '*'
-      cache-control:
-      - max-age=548
-      etag:
-      - W/"74-uYd/TxZEF87Urak29pxyd08PwVE"
-      tk:
+      - nginx
+      Strict-Transport-Security:
+      - max-age=63072000; includeSubDomains
+      Tk:
       - N
-      x-frame-options:
+      X-Frame-Options:
       - DENY
+      X-RateLimit-Limit:
+      - '200'
+      X-RateLimit-Remaining:
+      - '199'
+      X-RateLimit-Reset:
+      - '1774697311'
+      cache-control:
+      - max-age=600
       x-powered-by:
       - PeerTube
     status:
       code: 200
       message: OK
 - request:
-    body: ''
+    body: null
     headers:
-      Accept:
-      - '*/*'
-      Accept-Encoding:
-      - gzip, deflate
       Connection:
-      - keep-alive
+      - close
       Host:
       - peertube.tv
       User-Agent:
-      - python-httpx/0.28.1
+      - Python-urllib/3.14
     method: GET
     uri: https://peertube.tv/nodeinfo/2.0.json
   response:
     body:
-      string: '{"version":"2.0","software":{"name":"peertube","version":"5.2.0"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"openRegistrations":false,"usage":{"users":{"total":609,"activeMonth":8,"activeHalfyear":35},"localPosts":18598,"localComments":93},"metadata":{"taxonomy":{"postsName":"Videos"},"nodeName":"PeerTube.TV","nodeDescription":"Videos
-        sharing & live streaming on free open source software PeerTube! No ads, no
-        tracking, no spam.","nodeConfig":{"search":{"remoteUri":{"users":true,"anonymous":false}},"plugin":{"registered":[{"npmName":"peertube-plugin-upload-instructions","name":"upload-instructions","version":"0.1.1","description":"Show
-        an instructions modal right before uploading","clientScripts":{"dist/common-client-plugin.js":{"script":"dist/common-client-plugin.js","scopes":["common"]}}},{"npmName":"peertube-plugin-custom-links","name":"custom-links","version":"0.0.10","description":"PeerTube
-        plugin that allows you to add custom links on the bottom of the menu","clientScripts":{"dist/common-client-plugin.js":{"script":"dist/common-client-plugin.js","scopes":["common"]}}},{"npmName":"peertube-plugin-glavliiit","name":"glavliiit","version":"0.0.10","description":"Enhanced
-        moderation tool for PeerTube","clientScripts":{}},{"npmName":"peertube-plugin-categories","name":"categories","version":"1.2.7","description":"Manage
-        video categories.","clientScripts":{"src/client/admin-plugin-settings.js":{"script":"src/client/admin-plugin-settings.js","scopes":["admin-plugin"]}}},{"npmName":"peertube-plugin-creative-commons","name":"creative-commons","version":"1.2.0","description":"Standardized
+      string: '{"version":"2.0","software":{"name":"peertube","version":"8.1.3"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":["atom1.0","rss2.0"]},"openRegistrations":false,"usage":{"users":{"total":609,"activeMonth":10,"activeHalfyear":35},"localPosts":688,"localComments":86},"metadata":{"taxonomy":{"postsName":"Videos"},"nodeName":"PeerTube.TV","nodeDescription":"Videos
+        sharing & live streaming on free open source software PeerTube!","nodeConfig":{"search":{"remoteUri":{"users":true,"anonymous":false}},"plugin":{"registered":[{"npmName":"peertube-plugin-creative-commons","name":"creative-commons","version":"1.2.0","description":"Standardized
         display of Creative Commons licenses. Uses short identifiers like CC BY-SA
-        4.0 instead of descriptive text.","clientScripts":{"client/video-watch-client-plugin.js":{"script":"client/video-watch-client-plugin.js","scopes":["video-watch"]}}},{"npmName":"peertube-plugin-social-sharing-rus","name":"social-sharing-rus","version":"0.11.0","description":"Share
-        a video or playlist URL on social media (Mastodon, WordPress, reddit, Twitter,
-        etc.)","clientScripts":{"dist/common-client-plugin.js":{"script":"dist/common-client-plugin.js","scopes":["common"]}}},{"npmName":"peertube-plugin-menu-items","name":"menu-items","version":"0.0.4","description":"PeerTube
-        plugin menu-items","clientScripts":{"dist/common-client-plugin.js":{"script":"dist/common-client-plugin.js","scopes":["common"]}}},{"npmName":"peertube-plugin-chapters","name":"chapters","version":"1.1.3","description":"PeerTube
-        chapter plugin","clientScripts":{"dist/client/video-watch-client-plugin.js":{"script":"dist/client/video-watch-client-plugin.js","scopes":["video-watch","embed"]},"dist/client/video-edit-client-plugin.js":{"script":"dist/client/video-edit-client-plugin.js","scopes":["video-edit"]}}},{"npmName":"peertube-plugin-simplelogo","name":"simplelogo","version":"0.0.5","description":"Plugin
-        that let you change logo and favicon on your PeerTube instance.","clientScripts":{"client/common-client-plugin.js":{"script":"client/common-client-plugin.js","scopes":["common"]}}},{"npmName":"peertube-plugin-video-annotation","name":"video-annotation","version":"0.0.7","description":"PeerTube
-        plugin video annotation","clientScripts":{"dist/embed-client-plugin.js":{"script":"dist/embed-client-plugin.js","scopes":["embed"]},"dist/video-edit-client-plugin.js":{"script":"dist/video-edit-client-plugin.js","scopes":["video-edit"]},"dist/video-watch-client-plugin.js":{"script":"dist/video-watch-client-plugin.js","scopes":["video-watch"]}}},{"npmName":"peertube-plugin-livechat","name":"livechat","version":"7.2.1","description":"PeerTube
-        plugin livechat: offers a way to embed a chat system into Peertube.","clientScripts":{"dist/client/videowatch-client-plugin.js":{"script":"dist/client/videowatch-client-plugin.js","scopes":["video-watch"]},"dist/client/common-client-plugin.js":{"script":"dist/client/common-client-plugin.js","scopes":["common"]},"dist/client/admin-plugin-client-plugin.js":{"script":"dist/client/admin-plugin-client-plugin.js","scopes":["admin-plugin"]}}}]},"theme":{"registered":[{"npmName":"peertube-theme-dark-evolution","name":"dark-evolution","version":"1.0.4","description":"Evolution
-        of the official PeerTube dark theme","css":["assets/style.css"],"clientScripts":{}},{"npmName":"peertube-theme-dark","name":"dark","version":"2.5.0","description":"PeerTube
-        dark theme","css":["assets/style.css"],"clientScripts":{}}],"default":"dark-evolution"},"email":{"enabled":true},"contactForm":{"enabled":true},"transcoding":{"hls":{"enabled":true},"webtorrent":{"enabled":true},"enabledResolutions":[144,240,360,480,720,1080]},"live":{"enabled":true,"transcoding":{"enabled":true,"enabledResolutions":[144,480,720,1080]}},"import":{"videos":{"http":{"enabled":true},"torrent":{"enabled":false}}},"autoBlacklist":{"videos":{"ofUsers":{"enabled":false}}},"avatar":{"file":{"size":{"max":4194304},"extensions":[".png",".jpeg",".jpg",".gif",".webp"]}},"video":{"image":{"extensions":[".png",".jpg",".jpeg",".webp"],"size":{"max":4194304}},"file":{"extensions":[".webm",".ogv",".ogg",".mp4",".mkv",".mov",".qt",".mqv",".m4v",".flv",".f4v",".wmv",".avi",".3gp",".3gpp",".3g2",".3gpp2",".nut",".mts",".m2ts",".mpv",".m2v",".m1v",".mpg",".mpe",".mpeg",".vob",".mxf",".mp3",".wma",".wav",".flac",".aac",".m4a",".ac3"]}},"videoCaption":{"file":{"size":{"max":20971520},"extensions":[".vtt",".srt"]}},"user":{"videoQuota":53687091200,"videoQuotaDaily":5368709120},"trending":{"videos":{"intervalDays":7}},"tracker":{"enabled":true}}}}'
+        4.0 instead of descriptive text.","clientScripts":{"client/video-watch-client-plugin.js":{"script":"client/video-watch-client-plugin.js","scopes":["video-watch"]}}},{"npmName":"peertube-plugin-categories","name":"categories","version":"1.2.7","description":"Manage
+        video categories.","clientScripts":{"src/client/admin-plugin-settings.js":{"script":"src/client/admin-plugin-settings.js","scopes":["admin-plugin"]}}},{"npmName":"peertube-plugin-video-annotation","name":"video-annotation","version":"0.2.0","description":"PeerTube
+        plugin video annotation","clientScripts":{"dist/embed-client-plugin.js":{"script":"dist/embed-client-plugin.js","scopes":["embed"]},"dist/video-edit-client-plugin.js":{"script":"dist/video-edit-client-plugin.js","scopes":["video-edit"]},"dist/video-watch-client-plugin.js":{"script":"dist/video-watch-client-plugin.js","scopes":["video-watch"]}}}]},"theme":{"registered":[{"npmName":"peertube-theme-dark","name":"dark","version":"3.0.3","description":"PeerTube
+        dark theme","css":["assets/style.css"],"clientScripts":{}}],"default":"default"},"email":{"enabled":true},"contactForm":{"enabled":true},"transcoding":{"hls":{"enabled":true},"web_videos":{"enabled":true},"enabledResolutions":[360]},"live":{"enabled":false,"transcoding":{"enabled":true,"enabledResolutions":[144,480,720,1080]}},"import":{"videos":{"http":{"enabled":true},"torrent":{"enabled":false}}},"autoBlacklist":{"videos":{"ofUsers":{"enabled":false}}},"avatar":{"file":{"size":{"max":8388608},"extensions":[".png",".jpeg",".jpg",".gif",".webp"]}},"video":{"image":{"extensions":[".png",".jpg",".jpeg",".webp"],"size":{"max":8388608}},"file":{"extensions":[".webm",".ogv",".ogg",".mp4",".mkv",".mov",".qt",".mqv",".m4v",".flv",".f4v",".wmv",".avi",".3gp",".3gpp",".3g2",".3gpp2",".nut",".mts",".ts",".m2ts",".mpv",".m2v",".m1v",".mpg",".mpe",".mpeg",".vob",".mxf",".mp3",".wma",".wav",".flac",".aac",".m4a",".ac3"]}},"videoCaption":{"file":{"size":{"max":20971520},"extensions":[".vtt",".srt"]}},"user":{"videoQuota":53687091200,"videoQuotaDaily":5368709120},"trending":{"videos":{"intervalDays":7}},"tracker":{"enabled":true}}}}'
     headers:
       Access-Control-Allow-Origin:
       - '*'
       Connection:
-      - keep-alive
+      - close
       Content-Length:
-      - '5567'
+      - '2859'
       Content-Type:
       - application/json; charset=utf-8; profile="http://nodeinfo.diaspora.software/ns/schema/2.0#"
       Date:
-      - Thu, 04 Dec 2025 12:17:47 GMT
+      - Sat, 28 Mar 2026 11:28:20 GMT
       ETag:
-      - W/"15bf-UHcLfIV97HliD7E2eKuWJsf3iEQ"
+      - W/"b2b-g18XMBMf5sGTfPJOaHXRzYFpIwA"
       Server:
-      - nginx/1.18.0 (Ubuntu)
+      - nginx
+      Strict-Transport-Security:
+      - max-age=63072000; includeSubDomains
       Tk:
       - N
       X-Frame-Options:
       - DENY
+      X-RateLimit-Limit:
+      - '50'
+      X-RateLimit-Remaining:
+      - '49'
+      X-RateLimit-Reset:
+      - '1774697311'
       cache-control:
       - max-age=600
       x-powered-by:

tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[tailscale.com].yml (0) → tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[tailscale.com].yml (92014)

diff --git a/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[tailscale.com].yml b/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[tailscale.com].yml
new file mode 100644
index 0000000..fb40254
--- /dev/null
+++ b/tests/fixtures/cassettes/TestIsMastodonHost.test_non_mastodon_servers[tailscale.com].yml
@@ -0,0 +1,876 @@
+interactions:
+- request:
+    body: null
+    headers:
+      Connection:
+      - close
+      Host:
+      - tailscale.com
+      User-Agent:
+      - Python-urllib/3.14
+    method: GET
+    uri: https://tailscale.com/.well-known/nodeinfo
+  response:
+    body:
+      string: "<!DOCTYPE html><html><head><meta charSet=\"utf-8\"/><title>404</title><meta
+        name=\"robots\" content=\"index,follow\"/><meta name=\"description\" content=\"Securely
+        connect to anything on the internet with Tailscale. Built on WireGuard\xAE\uFE0F,
+        Tailscale enables you to make finely configurable connections, secured end-to-end
+        according to zero trust principles, between any resources on any infrastructure.\"/><meta
+        property=\"og:title\" content=\"404\"/><meta property=\"og:description\" content=\"Securely
+        connect to anything on the internet with Tailscale. Built on WireGuard\xAE\uFE0F,
+        Tailscale enables you to make finely configurable connections, secured end-to-end
+        according to zero trust principles, between any resources on any infrastructure.\"/><meta
+        property=\"og:url\" content=\"https://tailscale.com/404\"/><meta property=\"og:image\"
+        content=\"https://tailscale.com/api/og-image?id=747a1d74-fd7c-43c3-83f5-ae55218823dd\"/><link
+        rel=\"canonical\" href=\"https://tailscale.com/404\"/><link rel=\"alternate\"
+        type=\"application/rss+xml\" href=\"https://tailscale.com/blog/index.xml\"/><link
+        rel=\"alternate\" type=\"application/rss+xml\" href=\"https://tailscale.com/changelog/index.xml\"/><link
+        rel=\"alternate\" type=\"application/rss+xml\" href=\"https://tailscale.com/security-bulletins/index.xml\"/><meta
+        name=\"viewport\" content=\"initial-scale=1.0, width=device-width, maximum-scale=1\"/><link
+        rel=\"icon\" href=\"/favicon.png\" type=\"image/png\"/><link rel=\"icon\"
+        href=\"/favicon.svg\" type=\"image/svg+xml\"/><meta name=\"msapplication-TileColor\"
+        content=\"#492847\"/><meta name=\"theme-color\" content=\"#ffffff\"/><script
+        async=\"\" src=\"https://bwa.marketplace.awsstatic.com/assets/partner.js\"></script><meta
+        name=\"twitter:card\" content=\"summary_large_image\"/><meta name=\"twitter:title\"
+        content=\"404\"/><meta name=\"twitter:image\" content=\"https://tailscale.com/api/og-image?id=747a1d74-fd7c-43c3-83f5-ae55218823dd\"/><meta
+        name=\"twitter:description\" content=\"Securely connect to anything on the
+        internet with Tailscale. Built on WireGuard\xAE\uFE0F, Tailscale enables you
+        to make finely configurable connections, secured end-to-end according to zero
+        trust principles, between any resources on any infrastructure.\"/><meta name=\"twitter:site\"
+        content=\"@tailscale\"/><meta name=\"next-head-count\" content=\"23\"/><link
+        rel=\"preload\" href=\"/_next/static/media/97a52bce187043ec-s.p.woff2\" as=\"font\"
+        type=\"font/woff2\" crossorigin=\"anonymous\" data-next-font=\"size-adjust\"/><link
+        rel=\"preload\" href=\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\" as=\"font\"
+        type=\"font/woff2\" crossorigin=\"anonymous\" data-next-font=\"size-adjust\"/><link
+        rel=\"preload\" href=\"/_next/static/css/d9b50c7edadb4b9c.css\" as=\"style\"/><link
+        rel=\"stylesheet\" href=\"/_next/static/css/d9b50c7edadb4b9c.css\" data-n-g=\"\"/><link
+        rel=\"preload\" href=\"/_next/static/css/9eee414ec9ffd447.css\" as=\"style\"/><link
+        rel=\"stylesheet\" href=\"/_next/static/css/9eee414ec9ffd447.css\" data-n-p=\"\"/><noscript
+        data-n-css=\"\"></noscript><script defer=\"\" nomodule=\"\" src=\"/_next/static/chunks/polyfills-42372ed130431b0a.js\"></script><script
+        src=\"/_next/static/chunks/webpack-7531eb7e1d335cd8.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/framework-2f437cbb805415a5.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/main-0d17d82c40603f51.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/pages/_app-f80bd9fe7679a6c7.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/942-08460e3e449dc5c5.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/2962-c70fc1b17df9e34c.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/1604-c7588012aea9ac3b.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/895-f79a93f5c02a5693.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/8148-65f6cc3bf9da352f.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/2099-6f8261a6895d4a7e.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/2737-f9cf8578e879d066.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/6772-4a704c5f2497e9ae.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/5525-ae3805a05aa422a2.js\" defer=\"\"></script><script
+        src=\"/_next/static/chunks/pages/404-60de5b8794546a8b.js\" defer=\"\"></script><script
+        src=\"/_next/static/yXNXD6wKMziT90Wz_CAoa/_buildManifest.js\" defer=\"\"></script><script
+        src=\"/_next/static/yXNXD6wKMziT90Wz_CAoa/_ssgManifest.js\" defer=\"\"></script><style
+        id=\"__jsx-1394014874\">:root{--font-inter:'__Inter_e10f34', '__Inter_Fallback_e10f34';--font-mdio:'__MDIOFont_8d6c39',
+        '__MDIOFont_Fallback_8d6c39'}</style></head><body><div id=\"__next\"><!--$--><!--/$--><div
+        class=\"sticky top-0 z-[20000]\"><div class=\"z-[20000] w-full p-4 font-mdio
+        text-xs uppercase !tracking-[0.6px] xl-small:p-1.5 bg-gray-700 text-white\"><div
+        class=\"mx-auto flex w-full max-w-[1360px] items-center justify-center px-6
+        xl-small:max-w-[1440px] xl-small:justify-between xl-small:px-16\"><div><a
+        class=\"group flex flex-wrap items-center justify-center gap-x-2 text-pretty
+        pt-0.5 text-center font-medium text-white sm:text-left\" href=\"https://tailscale.com/blog/aperture-self-serve/?utm_source=announcement-bar&amp;utm_medium=content&amp;utm_campaign=aperture-self-serve\">APERTURE
+        IS NOW AVAILABLE - START BUILDING WITH AI SAFELY IN MINUTES, NO WAITLIST.<span
+        class=\"pl-2 text-gray-0/80 underline group-hover:no-underline\">Read more
+        \u2192</span></a></div><nav class=\"hidden xl-small:block\"><ul class=\"flex
+        gap-6\"><li><a class=\"block py-3.5 font-medium text-gray-0/80 hover:underline\"
+        href=\"/blog\">Blog</a></li><li><a class=\"block py-3.5 font-medium text-gray-0/80
+        hover:underline\" href=\"/docs\">Docs</a></li><li><a class=\"block py-3.5
+        font-medium text-gray-0/80 hover:underline\" href=\"/download\">Download</a></li><li><a
+        class=\"block py-3.5 font-medium text-gray-0/80 hover:underline\" href=\"/contact/sales\">Contact
+        Sales</a></li></ul></nav></div></div><header class=\"bg-white transition-colors
+        duration-300\"><div class=\"mx-auto flex h-[75px] w-full max-w-[1360px] items-center
+        justify-between gap-[4px] px-6 md:max-w-[1440px] lg:px-16\"><a href=\"/\"><svg
+        width=\"145\" height=\"28\" viewBox=\"0 0 145 28\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M3.5 17.5C5.43299 17.5 6.99999 15.933 6.99999 14C6.99999 12.067 5.43299
+        10.5 3.5 10.5C1.567 10.5 0 12.067 0 14C0 15.933 1.567 17.5 3.5 17.5Z\" fill=\"#232222\"></path><path
+        d=\"M14 17.5C15.933 17.5 17.5 15.933 17.5 14C17.5 12.067 15.933 10.5 14 10.5C12.067
+        10.5 10.5 12.067 10.5 14C10.5 15.933 12.067 17.5 14 17.5Z\" fill=\"#232222\"></path><path
+        d=\"M14 28C15.933 28 17.5 26.433 17.5 24.5C17.5 22.567 15.933 21 14 21C12.067
+        21 10.5 22.567 10.5 24.5C10.5 26.433 12.067 28 14 28Z\" fill=\"#232222\"></path><path
+        d=\"M24.5 17.5C26.433 17.5 28 15.933 28 14C28 12.067 26.433 10.5 24.5 10.5C22.567
+        10.5 21 12.067 21 14C21 15.933 22.567 17.5 24.5 17.5Z\" fill=\"#232222\"></path><g
+        opacity=\"0.4\"><path d=\"M3.5 28C5.43299 28 6.99999 26.433 6.99999 24.5C6.99999
+        22.567 5.43299 21 3.5 21C1.567 21 0 22.567 0 24.5C0 26.433 1.567 28 3.5 28Z\"
+        fill=\"#232222\"></path><path d=\"M24.5 28C26.433 28 28 26.433 28 24.5C28
+        22.567 26.433 21 24.5 21C22.567 21 21 22.567 21 24.5C21 26.433 22.567 28 24.5
+        28Z\" fill=\"#232222\"></path><path d=\"M3.5 6.99999C5.43299 6.99999 6.99999
+        5.43299 6.99999 3.5C6.99999 1.567 5.43299 0 3.5 0C1.567 0 0 1.567 0 3.5C0
+        5.43299 1.567 6.99999 3.5 6.99999Z\" fill=\"#232222\"></path><path d=\"M14
+        6.99999C15.933 6.99999 17.5 5.43299 17.5 3.5C17.5 1.567 15.933 0 14 0C12.067
+        0 10.5 1.567 10.5 3.5C10.5 5.43299 12.067 6.99999 14 6.99999Z\" fill=\"#232222\"></path><path
+        d=\"M24.5 6.99999C26.433 6.99999 28 5.43299 28 3.5C28 1.567 26.433 0 24.5
+        0C22.567 0 21 1.567 21 3.5C21 5.43299 22.567 6.99999 24.5 6.99999Z\" fill=\"#232222\"></path></g><path
+        d=\"M46.1746 24.5C47.0875 24.5 47.8293 24.4144 48.7137 24.2432V20.9334C48.1717
+        21.1331 47.5725 21.1902 47.0019 21.1902C45.604 21.1902 45.0904 20.5054 45.0904
+        19.1929V12.4592H48.7137V9.14945H45.0904V4.24185H41.0962V9.14945H38.5V12.4592H41.0962V19.5638C41.0962
+        22.7024 42.751 24.5 46.1746 24.5Z\" fill=\"#232222\"></path><path d=\"M55.2368
+        24.5C57.3766 24.5 58.8031 23.7867 59.5163 22.6739C59.5734 23.159 59.7446 23.8152
+        59.9728 24.2147H63.5676C63.3679 23.5299 63.2252 22.4456 63.2252 21.7323V13.9144C63.2252
+        10.6902 60.9143 8.86412 57.0057 8.86412C54.0386 8.86412 51.7277 9.9769 50.4438
+        11.6033L52.7262 13.8573C53.7533 12.716 55.0657 12.1168 56.6633 12.1168C58.6034
+        12.1168 59.4593 12.7731 59.4593 13.7432C59.4593 14.5706 58.8887 15.1413 55.8074
+        15.1413C52.8403 15.1413 49.8447 16.3682 49.8447 19.7921C49.8447 22.9592 52.1271
+        24.5 55.2368 24.5ZM56.0357 21.4755C54.4951 21.4755 53.7818 20.8193 53.7818
+        19.6494C53.7818 18.6223 54.6377 17.9375 56.0642 17.9375C58.3466 17.9375 58.9743
+        17.7948 59.4593 17.3098V18.5367C59.4593 20.163 58.0898 21.4755 56.0357 21.4755Z\"
+        fill=\"#232222\"></path><path d=\"M65.8217 7.23777H69.9871V3.5H65.8217V7.23777ZM65.9073
+        24.2147H69.9015V9.14945H65.9073V24.2147Z\" fill=\"#232222\"></path><path d=\"M72.8113
+        24.2147H76.8055V3.95652H72.8113V24.2147Z\" fill=\"#232222\"></path><path d=\"M85.1075
+        24.5C89.5011 24.5 91.755 22.1888 91.755 19.7636C91.755 17.5666 90.6423 15.9402
+        86.9905 15.284C84.4228 14.8274 82.8251 14.2568 82.8251 13.3723C82.8251 12.6019
+        83.7381 12.0598 85.2787 12.0598C86.6481 12.0598 87.7893 12.5163 88.6452 13.5149L91.1844
+        11.375C89.9005 9.77717 87.7893 8.86412 85.2787 8.86412C81.4271 8.86412 79.0306
+        10.9185 79.0306 13.4293C79.0306 16.1685 81.5412 17.3954 84.2516 17.8804C86.5055
+        18.2799 87.7608 18.7079 87.7608 19.678C87.7608 20.5054 86.8763 21.1902 85.1931
+        21.1902C83.5383 21.1902 82.2545 20.4198 81.6554 19.2785L78.2888 20.8763C79.1162
+        22.9307 81.9407 24.5 85.1075 24.5Z\" fill=\"#232222\"></path><path d=\"M100.685
+        24.5C103.538 24.5 105.592 23.3587 107.132 20.7907L103.937 19.1644C103.338
+        20.3628 102.368 21.1902 100.685 21.1902C98.1455 21.1902 96.776 19.1359 96.776
+        16.6535C96.776 14.1712 98.2311 12.1739 100.685 12.1739C102.225 12.1739 103.252
+        13.0014 103.851 14.2568L107.075 12.5448C105.991 10.1766 103.851 8.86412 100.685
+        8.86412C95.4636 8.86412 92.7818 12.6875 92.7818 16.6535C92.7818 20.9619 96.0342
+        24.5 100.685 24.5Z\" fill=\"#232222\"></path><path d=\"M113.495 24.5C115.635
+        24.5 117.061 23.7867 117.774 22.6739C117.831 23.159 118.003 23.8152 118.231
+        24.2147H121.826C121.626 23.5299 121.483 22.4456 121.483 21.7323V13.9144C121.483
+        10.6902 119.172 8.86412 115.264 8.86412C112.297 8.86412 109.986 9.9769 108.702
+        11.6033L110.984 13.8573C112.011 12.716 113.324 12.1168 114.921 12.1168C116.861
+        12.1168 117.717 12.7731 117.717 13.7432C117.717 14.5706 117.147 15.1413 114.065
+        15.1413C111.098 15.1413 108.103 16.3682 108.103 19.7921C108.103 22.9592 110.385
+        24.5 113.495 24.5ZM114.294 21.4755C112.753 21.4755 112.04 20.8193 112.04 19.6494C112.04
+        18.6223 112.896 17.9375 114.322 17.9375C116.605 17.9375 117.232 17.7948 117.717
+        17.3098V18.5367C117.717 20.163 116.348 21.4755 114.294 21.4755Z\" fill=\"#232222\"></path><path
+        d=\"M123.831 24.2147H127.825V3.95652H123.831V24.2147Z\" fill=\"#232222\"></path><path
+        d=\"M137.411 24.5C140.35 24.5 142.718 23.3301 144.03 21.2473L141.006 19.3071C140.207
+        20.5625 139.151 21.2473 137.411 21.2473C135.442 21.2473 134.016 20.163 133.645
+        18.0516H145V16.6535C145 12.6875 142.575 8.86412 137.382 8.86412C132.447 8.86412
+        129.765 12.716 129.765 16.6821C129.765 22.3315 134.016 24.5 137.411 24.5ZM133.788
+        14.913C134.415 13.0014 135.728 12.1168 137.468 12.1168C139.437 12.1168 140.635
+        13.2867 141.034 14.913H133.788Z\" fill=\"#232222\"></path></svg></a><div class=\"flex
+        w-full items-center justify-end gap-3 xl-small:justify-between\"><nav class=\"website-nav
+        m-auto hidden xl-small:relative xl-small:block\"><ul class=\"flex gap-x-[4px]\"><li><button
+        type=\"button\" class=\"flex items-center gap-[4px] rounded-md px-3 py-2.5
+        text-sm font-medium hover:bg-gray-200\">Platform<svg width=\"14\" height=\"14\"
+        viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></button><div
+        class=\"pointer-events-none absolute left-1/2 top-full z-[100] mt-3 -translate-x-1/2
+        pt-4 opacity-0\"><div class=\"overflow-hidden rounded-2xl border border-gray-200
+        shadow-8\"><div class=\"grid auto-cols-[268px] grid-flow-col gap-4 border-b
+        border-gray-200 bg-white p-8 shadow-2\"><div class=\"flex flex-col gap-4\"><div
+        class=\"flex items-center gap-2.5 px-3\"><p class=\"whitespace-nowrap font-mdio
+        text-[14px] font-medium uppercase !tracking-[0.6px] text-gray-700/80\">Meet
+        Tailscale</p><div class=\"h-px w-full bg-gray-200\"></div></div><ul class=\"flex
+        flex-col gap-1\"><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;How Tailscale Works&quot;}\" href=\"/blog/how-tailscale-works\">How
+        Tailscale Works</a></li><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;WireGuard\xAE for Enterprises&quot;}\" href=\"/wireguard-vpn\">WireGuard\xAE
+        for Enterprises</a></li><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Features&quot;}\" href=\"/features\">Features</a></li><li><a class=\"block
+        rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Integrations&quot;}\"
+        href=\"/integrations\">Integrations</a></li><li><a class=\"block rounded-md
+        p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Docs&quot;}\"
+        href=\"/docs\">Docs</a></li><li><a class=\"block rounded-md p-3 text-base
+        font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Download&quot;}\" href=\"/download\">Download</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Compare
+        Tailscale&quot;}\" href=\"/compare\">Compare Tailscale</a></li></ul></div><div
+        class=\"flex flex-col gap-4\"><div class=\"flex items-center gap-2.5 px-3\"><p
+        class=\"whitespace-nowrap font-mdio text-[14px] font-medium uppercase !tracking-[0.6px]
+        text-gray-700/80\">Products</p><div class=\"h-px w-full bg-gray-200\"></div></div><ul
+        class=\"flex flex-col gap-1\"><li><a class=\"block rounded-md p-3 text-base
+        font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Business VPN&quot;}\" href=\"/use-cases/business-vpn\">Business
+        VPN</a></li><li><a class=\"block rounded-md p-3 text-base font-medium text-gray-700
+        hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;PAM&quot;}\" href=\"/use-cases/pam\">PAM</a></li><li><a class=\"block
+        rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;CI/CD Connectivity&quot;}\"
+        href=\"/use-cases/ci-cd\">CI/CD Connectivity</a></li><li><a class=\"block
+        rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Secure Access
+        to AI&quot;}\" href=\"/use-cases/securing-ai\">Secure Access to AI</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Cloud
+        Connectivity&quot;}\" href=\"/use-cases/cloud-connectivity\">Cloud Connectivity</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Workload
+        Connectivity&quot;}\" href=\"/use-cases/workload-connectivity\">Workload Connectivity</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Edge
+        &amp; IoT&quot;}\" href=\"/use-cases/edge-iot\">Edge &amp; IoT</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Homelab&quot;}\"
+        href=\"/use-cases/homelab\">Homelab</a></li></ul></div><a class=\"flex flex-col
+        self-stretch overflow-hidden rounded-md border border-gray-200 bg-gray-100
+        shadow-2\" href=\"https://tailscale.com/use-cases/securing-ai\"><div class=\"relative
+        flex flex-1 items-center\"><img alt=\"aperture dashboard\" loading=\"lazy\"
+        width=\"268\" height=\"150\" decoding=\"async\" data-nimg=\"1\" class=\"h-auto
+        w-full rounded-none border-none object-cover\" style=\"color:transparent\"
+        src=\"https://cdn.sanity.io/images/w77i7m8x/production-v2/7fbf14ac75bdf258eeff9efb2a2d5bbbf2e87098-266x342.svg\"/></div><div
+        class=\"bg-gray-50 p-8\"><p class=\"mb-1 font-mdio text-[14px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700\">Aperture by Tailscale</p><p class=\"text-base
+        text-gray-700/80\">Unified AI governance for AI agents and users.</p></div></a></div><div
+        class=\"bg-gray-50 p-8\"><div class=\"flex items-center justify-between\"><div
+        class=\"flex flex-col gap-1\"><p class=\"font-mdio text-[14px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700\">Tailscale Winter Update</p><p
+        class=\"text-base text-gray-700/80\">The latest improvements on Aperture,
+        Peer Relays, Services, and more.</p></div><a class=\"inline-flex h-9 shrink-0
+        items-center justify-center rounded-md border border-gray-800 bg-gray-800
+        px-3 text-base font-medium text-white shadow-2 transition-all duration-200
+        hover:opacity-80 hover:shadow-4\" href=\"https://tailscale.com/winter-update-week-26\">Read
+        more</a></div></div></div></div></li><li><button type=\"button\" class=\"flex
+        items-center gap-[4px] rounded-md px-3 py-2.5 text-sm font-medium hover:bg-gray-200\">Customer
+        Stories<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\"
+        xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path><path
+        d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\" style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></button><div
+        class=\"pointer-events-none absolute left-1/2 top-full z-[100] mt-3 -translate-x-1/2
+        pt-4 opacity-0\"><div class=\"overflow-hidden rounded-2xl border border-gray-200
+        shadow-8\"><div class=\"grid auto-cols-[268px] grid-flow-col gap-4 border-b
+        border-gray-200 bg-white p-8 shadow-2\"><div class=\"flex flex-col gap-4\"><div
+        class=\"flex items-center gap-2.5 px-3\"><p class=\"whitespace-nowrap font-mdio
+        text-[14px] font-medium uppercase !tracking-[0.6px] text-gray-700/80\">Customer
+        Stories</p><div class=\"h-px w-full bg-gray-200\"></div></div><ul class=\"flex
+        flex-col gap-1\"><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Instacart&quot;}\" href=\"/customers/instacart\">Instacart</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Cribl&quot;}\"
+        href=\"/customers/cribl\">Cribl</a></li><li><a class=\"block rounded-md p-3
+        text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Mercury&quot;}\"
+        href=\"/customers/mercury\">Mercury</a></li><li><a class=\"block rounded-md
+        p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Hugging Face&quot;}\"
+        href=\"/customers/hugging-face\">Hugging Face</a></li><li><a class=\"block
+        rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;All Customer Stories&quot;}\"
+        href=\"/customers\">All Customer Stories</a></li></ul></div></div></div></div></li><li><button
+        type=\"button\" class=\"flex items-center gap-[4px] rounded-md px-3 py-2.5
+        text-sm font-medium hover:bg-gray-200\">Community<svg width=\"14\" height=\"14\"
+        viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></button><div
+        class=\"pointer-events-none absolute left-1/2 top-full z-[100] mt-3 -translate-x-1/2
+        pt-4 opacity-0\"><div class=\"overflow-hidden rounded-2xl border border-gray-200
+        shadow-8\"><div class=\"grid auto-cols-[268px] grid-flow-col gap-4 border-b
+        border-gray-200 bg-white p-8 shadow-2\"><div class=\"flex flex-col gap-4\"><div
+        class=\"flex items-center gap-2.5 px-3\"><p class=\"whitespace-nowrap font-mdio
+        text-[14px] font-medium uppercase !tracking-[0.6px] text-gray-700/80\">Join
+        the Community</p><div class=\"h-px w-full bg-gray-200\"></div></div><ul class=\"flex
+        flex-col gap-1\"><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Tailscale Insiders&quot;}\" href=\"/insiders-program\">Tailscale Insiders</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Community
+        Projects&quot;}\" href=\"/community/community-projects\">Community Projects</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Bring
+        Tailscale to Work&quot;}\" href=\"/bring-tailscale-to-work\">Bring Tailscale
+        to Work</a></li></ul></div><div class=\"flex flex-col gap-4\"><div class=\"flex
+        items-center gap-2.5 px-3\"><p class=\"whitespace-nowrap font-mdio text-[14px]
+        font-medium uppercase !tracking-[0.6px] text-gray-700/80\">Events</p><div
+        class=\"h-px w-full bg-gray-200\"></div></div><ul class=\"flex flex-col gap-1\"><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Events
+        and Webinars&quot;}\" href=\"/events-webinars\">Events and Webinars</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;TailscaleUp&quot;}\"
+        href=\"/tailscaleup\">TailscaleUp</a></li></ul></div><div class=\"flex flex-col
+        gap-4\"><div class=\"flex items-center gap-2.5 px-3\"><p class=\"whitespace-nowrap
+        font-mdio text-[14px] font-medium uppercase !tracking-[0.6px] text-gray-700/80\">Learn
+        more</p><div class=\"h-px w-full bg-gray-200\"></div></div><ul class=\"flex
+        flex-col gap-1\"><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Docs&quot;}\" href=\"/docs\">Docs</a></li><li><a class=\"block rounded-md
+        p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Blog&quot;}\"
+        href=\"/blog\">Blog</a></li><li><a class=\"block rounded-md p-3 text-base
+        font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Changelog&quot;}\" href=\"/changelog\">Changelog</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Press&quot;}\"
+        href=\"/press\">Press</a></li></ul></div></div><div class=\"bg-gray-50 p-8\"><div
+        class=\"flex items-center justify-between\"><div class=\"flex flex-col gap-1\"><p
+        class=\"font-mdio text-[14px] font-medium uppercase !tracking-[0.6px] text-gray-700\">Join
+        us at TailscaleUp</p><p class=\"text-base text-gray-700/80\">Tailscale\u2019s
+        conference for engineering, security, and IT leaders.</p></div><a class=\"inline-flex
+        h-9 shrink-0 items-center justify-center rounded-md border border-gray-800
+        bg-gray-800 px-3 text-base font-medium text-white shadow-2 transition-all
+        duration-200 hover:opacity-80 hover:shadow-4\" href=\"https://tailscale.com/tailscaleup\">Learn
+        more</a></div></div></div></div></li><li><button type=\"button\" class=\"flex
+        items-center gap-[4px] rounded-md px-3 py-2.5 text-sm font-medium hover:bg-gray-200\">Partnerships<svg
+        width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></button><div
+        class=\"pointer-events-none absolute left-1/2 top-full z-[100] mt-3 -translate-x-1/2
+        pt-4 opacity-0\"><div class=\"overflow-hidden rounded-2xl border border-gray-200
+        shadow-8\"><div class=\"grid auto-cols-[268px] grid-flow-col gap-4 border-b
+        border-gray-200 bg-white p-8 shadow-2\"><div class=\"flex flex-col gap-4\"><div
+        class=\"flex items-center gap-2.5 px-3\"><p class=\"whitespace-nowrap font-mdio
+        text-[14px] font-medium uppercase !tracking-[0.6px] text-gray-700/80\">Partner
+        Opportunities</p><div class=\"h-px w-full bg-gray-200\"></div></div><ul class=\"flex
+        flex-col gap-1\"><li><a class=\"block rounded-md p-3 text-base font-medium
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Become a Partner&quot;}\" href=\"/partnerships\">Become a Partner</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Community
+        Projects&quot;}\" href=\"/community/community-projects\">Community Projects</a></li><li><a
+        class=\"block rounded-md p-3 text-base font-medium text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Integrations&quot;}\"
+        href=\"/integrations\">Integrations</a></li><li><a class=\"block rounded-md
+        p-3 text-base font-medium text-gray-700 hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Contact Partnerships
+        Team&quot;}\" href=\"/contact/partnerships\">Contact Partnerships Team</a></li></ul></div></div></div></div></li><li><a
+        href=\"/pricing\" class=\"flex items-center gap-4 rounded-md px-3 py-2.5 text-sm
+        font-medium hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Pricing&quot;}\">Pricing</a></li></ul></nav><nav class=\"hidden sm:ml-auto
+        sm:block lg:ml-0\"><ul class=\"flex items-center gap-x-[4px] font-medium\"><li><a
+        href=\"https://login.tailscale.com/welcome\" class=\"block rounded-md px-3
+        py-2.5 text-sm hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Login&quot;}\">Login</a></li><li><a class=\"inline-flex h-9 items-center
+        justify-center rounded-[0.5rem] border border-gray-800 bg-gray-800 px-3 text-base
+        font-medium text-white shadow-2 transition-all duration-200 hover:opacity-80
+        hover:shadow-4\" href=\"https://login.tailscale.com/start\">Get started -
+        it&#x27;s free!</a></li></ul></nav><button type=\"button\" class=\"h-[36px]
+        rounded-[0.5rem] bg-gray-800 px-[5px] xl-small:hidden\"><svg width=\"24\"
+        height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M4 12H20\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M4 6H20\" stroke=\"#fff\" stroke-width=\"2\"
+        stroke-linecap=\"round\" stroke-linejoin=\"round\"></path><path d=\"M4 18H20\"
+        stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></svg></button></div></div></header><div
+        class=\"pointer-events-none absolute left-0 top-full w-full bg-white opacity-0
+        transition-opacity duration-150 md:hidden\"><div class=\"bg-gray-700\"><nav><ul
+        class=\"flex justify-center gap-6\"><li><a class=\"block py-2.5 font-mdio
+        text-xs uppercase !tracking-[0.6px] text-gray-0/80 hover:underline\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Blog&quot;}\"
+        href=\"/blog\">Blog</a></li><li><a class=\"block py-2.5 font-mdio text-xs
+        uppercase !tracking-[0.6px] text-gray-0/80 hover:underline\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Docs&quot;}\"
+        href=\"/docs\">Docs</a></li><li><a class=\"block py-2.5 font-mdio text-xs
+        uppercase !tracking-[0.6px] text-gray-0/80 hover:underline\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Download&quot;}\"
+        href=\"/download\">Download</a></li><li><a class=\"block py-2.5 font-mdio
+        text-xs uppercase !tracking-[0.6px] text-gray-0/80 hover:underline\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Contact Sales&quot;}\"
+        href=\"/contact/sales\">Contact Sales</a></li></ul></nav></div><nav class=\"max-h-[60vh]
+        overflow-auto rounded-b-md p-6\"><details class=\"group\"><summary class=\"flex
+        items-center justify-between rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] hover:bg-gray-200 group-open:bg-gray-200\">Platform<span
+        class=\"relative\"><span class=\"group-open:hidden\"><svg width=\"14\" height=\"14\"
+        viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span><span
+        class=\"hidden group-open:block\"><svg width=\"14\" height=\"14\" viewBox=\"0
+        0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.91675
+        7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:0;transform:scaleY(0);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span></span></summary><div
+        class=\"mb-4 border-b border-gray-200 py-4\"><div class=\"mb-6\"><p class=\"mb-3
+        flex items-center gap-2.5 whitespace-nowrap px-2 font-mdio text-[12px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700/80 after:h-px after:w-full after:bg-gray-200
+        after:content-[&#x27;&#x27;]\">Meet Tailscale</p><ul><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;How Tailscale Works&quot;}\" href=\"/blog/how-tailscale-works\">How
+        Tailscale Works</a></li><li class=\"space-y-1\"><a class=\"block rounded-md
+        px-2 py-3 text-[14px] font-medium tracking-[-0.14px] text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;WireGuard\xAE
+        for Enterprises&quot;}\" href=\"/wireguard-vpn\">WireGuard\xAE for Enterprises</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Features&quot;}\" href=\"/features\">Features</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Integrations&quot;}\" href=\"/integrations\">Integrations</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Docs&quot;}\" href=\"/docs\">Docs</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Download&quot;}\" href=\"/download\">Download</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Compare Tailscale&quot;}\"
+        href=\"/compare\">Compare Tailscale</a></li></ul></div><div class=\"mb-6\"><p
+        class=\"mb-3 flex items-center gap-2.5 whitespace-nowrap px-2 font-mdio text-[12px]
+        font-medium uppercase !tracking-[0.6px] text-gray-700/80 after:h-px after:w-full
+        after:bg-gray-200 after:content-[&#x27;&#x27;]\">Products</p><ul><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Business VPN&quot;}\" href=\"/use-cases/business-vpn\">Business VPN</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;PAM&quot;}\" href=\"/use-cases/pam\">PAM</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;CI/CD Connectivity&quot;}\"
+        href=\"/use-cases/ci-cd\">CI/CD Connectivity</a></li><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Secure Access to AI&quot;}\" href=\"/use-cases/securing-ai\">Secure
+        Access to AI</a></li><li class=\"space-y-1\"><a class=\"block rounded-md px-2
+        py-3 text-[14px] font-medium tracking-[-0.14px] text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Cloud
+        Connectivity&quot;}\" href=\"/use-cases/cloud-connectivity\">Cloud Connectivity</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Workload Connectivity&quot;}\"
+        href=\"/use-cases/workload-connectivity\">Workload Connectivity</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Edge &amp; IoT&quot;}\"
+        href=\"/use-cases/edge-iot\">Edge &amp; IoT</a></li><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Homelab&quot;}\" href=\"/use-cases/homelab\">Homelab</a></li></ul></div></div></details><details
+        class=\"group\"><summary class=\"flex items-center justify-between rounded-md
+        px-2 py-3 text-[14px] font-medium tracking-[-0.14px] hover:bg-gray-200 group-open:bg-gray-200\">Customer
+        Stories<span class=\"relative\"><span class=\"group-open:hidden\"><svg width=\"14\"
+        height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span><span
+        class=\"hidden group-open:block\"><svg width=\"14\" height=\"14\" viewBox=\"0
+        0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.91675
+        7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:0;transform:scaleY(0);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span></span></summary><div
+        class=\"mb-4 border-b border-gray-200 py-4\"><div class=\"mb-6\"><p class=\"mb-3
+        flex items-center gap-2.5 whitespace-nowrap px-2 font-mdio text-[12px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700/80 after:h-px after:w-full after:bg-gray-200
+        after:content-[&#x27;&#x27;]\">Customer Stories</p><ul><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Instacart&quot;}\" href=\"/customers/instacart\">Instacart</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Cribl&quot;}\" href=\"/customers/cribl\">Cribl</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Mercury&quot;}\" href=\"/customers/mercury\">Mercury</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Hugging Face&quot;}\" href=\"/customers/hugging-face\">Hugging
+        Face</a></li><li class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3
+        text-[14px] font-medium tracking-[-0.14px] text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;All
+        Customer Stories&quot;}\" href=\"/customers\">All Customer Stories</a></li></ul></div></div></details><details
+        class=\"group\"><summary class=\"flex items-center justify-between rounded-md
+        px-2 py-3 text-[14px] font-medium tracking-[-0.14px] hover:bg-gray-200 group-open:bg-gray-200\">Community<span
+        class=\"relative\"><span class=\"group-open:hidden\"><svg width=\"14\" height=\"14\"
+        viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span><span
+        class=\"hidden group-open:block\"><svg width=\"14\" height=\"14\" viewBox=\"0
+        0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.91675
+        7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:0;transform:scaleY(0);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span></span></summary><div
+        class=\"mb-4 border-b border-gray-200 py-4\"><div class=\"mb-6\"><p class=\"mb-3
+        flex items-center gap-2.5 whitespace-nowrap px-2 font-mdio text-[12px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700/80 after:h-px after:w-full after:bg-gray-200
+        after:content-[&#x27;&#x27;]\">Join the Community</p><ul><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Tailscale Insiders&quot;}\" href=\"/insiders-program\">Tailscale Insiders</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Community Projects&quot;}\"
+        href=\"/community/community-projects\">Community Projects</a></li><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Bring Tailscale to Work&quot;}\" href=\"/bring-tailscale-to-work\">Bring
+        Tailscale to Work</a></li></ul></div><div class=\"mb-6\"><p class=\"mb-3 flex
+        items-center gap-2.5 whitespace-nowrap px-2 font-mdio text-[12px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700/80 after:h-px after:w-full after:bg-gray-200
+        after:content-[&#x27;&#x27;]\">Events</p><ul><li class=\"space-y-1\"><a class=\"block
+        rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px] text-gray-700
+        hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Events and Webinars&quot;}\" href=\"/events-webinars\">Events and Webinars</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;TailscaleUp&quot;}\" href=\"/tailscaleup\">TailscaleUp</a></li></ul></div><div
+        class=\"mb-6\"><p class=\"mb-3 flex items-center gap-2.5 whitespace-nowrap
+        px-2 font-mdio text-[12px] font-medium uppercase !tracking-[0.6px] text-gray-700/80
+        after:h-px after:w-full after:bg-gray-200 after:content-[&#x27;&#x27;]\">Learn
+        more</p><ul><li class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3
+        text-[14px] font-medium tracking-[-0.14px] text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Docs&quot;}\"
+        href=\"/docs\">Docs</a></li><li class=\"space-y-1\"><a class=\"block rounded-md
+        px-2 py-3 text-[14px] font-medium tracking-[-0.14px] text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Blog&quot;}\"
+        href=\"/blog\">Blog</a></li><li class=\"space-y-1\"><a class=\"block rounded-md
+        px-2 py-3 text-[14px] font-medium tracking-[-0.14px] text-gray-700 hover:bg-gray-200\"
+        data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Changelog&quot;}\"
+        href=\"/changelog\">Changelog</a></li><li class=\"space-y-1\"><a class=\"block
+        rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px] text-gray-700
+        hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Press&quot;}\" href=\"/press\">Press</a></li></ul></div></div></details><details
+        class=\"group\"><summary class=\"flex items-center justify-between rounded-md
+        px-2 py-3 text-[14px] font-medium tracking-[-0.14px] hover:bg-gray-200 group-open:bg-gray-200\">Partnerships<span
+        class=\"relative\"><span class=\"group-open:hidden\"><svg width=\"14\" height=\"14\"
+        viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path
+        d=\"M2.91675 7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:1;transform:scaleY(1);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span><span
+        class=\"hidden group-open:block\"><svg width=\"14\" height=\"14\" viewBox=\"0
+        0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.91675
+        7H11.0834\" stroke=\"#2E2D2D\" stroke-width=\"1.16667\" stroke-linecap=\"round\"
+        stroke-linejoin=\"round\"></path><path d=\"M7 2.9165V11.0832\" stroke=\"#2E2D2D\"
+        stroke-width=\"1.16667\" stroke-linecap=\"round\" stroke-linejoin=\"round\"
+        style=\"opacity:0;transform:scaleY(0);transform-origin:center;transition:opacity
+        150ms ease-in-out, transform 150ms ease-in-out\"></path></svg></span></span></summary><div
+        class=\"mb-4 border-b border-gray-200 py-4\"><div class=\"mb-6\"><p class=\"mb-3
+        flex items-center gap-2.5 whitespace-nowrap px-2 font-mdio text-[12px] font-medium
+        uppercase !tracking-[0.6px] text-gray-700/80 after:h-px after:w-full after:bg-gray-200
+        after:content-[&#x27;&#x27;]\">Partner Opportunities</p><ul><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Become a Partner&quot;}\" href=\"/partnerships\">Become a Partner</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Community Projects&quot;}\"
+        href=\"/community/community-projects\">Community Projects</a></li><li class=\"space-y-1\"><a
+        class=\"block rounded-md px-2 py-3 text-[14px] font-medium tracking-[-0.14px]
+        text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Integrations&quot;}\" href=\"/integrations\">Integrations</a></li><li
+        class=\"space-y-1\"><a class=\"block rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] text-gray-700 hover:bg-gray-200\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Contact Partnerships Team&quot;}\"
+        href=\"/contact/partnerships\">Contact Partnerships Team</a></li></ul></div></div></details><a
+        class=\"flex justify-between rounded-md px-2 py-3 text-[14px] font-medium
+        tracking-[-0.14px] hover:bg-gray-200\" data-track=\"Link Clicked\" data-track-properties=\"{&quot;label&quot;:
+        &quot;Pricing&quot;}\" href=\"/pricing\">Pricing</a></nav><nav class=\"mx-6
+        border-t border-gray-200 py-6\"><ul class=\"flex items-center justify-between
+        gap-x-4 font-medium\"><li><a href=\"https://login.tailscale.com/welcome\"
+        class=\"block rounded-md px-3 py-2.5 text-sm hover:bg-gray-200\" data-track=\"Link
+        Clicked\" data-track-properties=\"{&quot;label&quot;: &quot;Login&quot;}\">Login</a></li><li><a
+        class=\"inline-flex h-9 items-center justify-center rounded-md border border-gray-800
+        bg-gray-800 px-3 text-base font-medium text-white shadow-2 transition-all
+        duration-200 hover:opacity-80 hover:shadow-4\" href=\"https://login.tailscale.com/start\">Get
+        started - it&#x27;s free!</a></li></ul></nav></div></div><div class=\"website-nav-backdrop
+        z-100 pointer-events-none fixed left-0 top-0 h-full w-full bg-gray-1000/25
+        opacity-0 transition-opacity duration-300\"></div><main><div class=\"p-top-115
+        bg-red-900\"><div class=\"container flex flex-wrap justify-between\"><div
+        class=\"flex-1 pt-12 lg:pt-[66px]\"><div class=\"mb-8 flex justify-center
+        md:justify-start lg:mb-[51px]\"><div class=\"md:-y-3 inline-flex items-center
+        justify-center gap-[17px] rounded-[10px] bg-red-600 p-3 md:px-5\"><img alt=\"404
+        icon\" loading=\"lazy\" width=\"27\" height=\"38\" decoding=\"async\" data-nimg=\"1\"
+        class=\"undefined\" style=\"color:transparent;background-size:cover;background-position:50%
+        50%;background-repeat:no-repeat;background-image:url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg
+        xmlns=&#x27;http://www.w3.org/2000/svg&#x27; viewBox=&#x27;0 0 27 38&#x27;%3E%3Cfilter
+        id=&#x27;b&#x27; color-interpolation-filters=&#x27;sRGB&#x27;%3E%3CfeGaussianBlur
+        stdDeviation=&#x27;20&#x27;/%3E%3CfeColorMatrix values=&#x27;1 0 0 0 0 0 1
+        0 0 0 0 0 1 0 0 0 0 0 100 -1&#x27; result=&#x27;s&#x27;/%3E%3CfeFlood x=&#x27;0&#x27;
+        y=&#x27;0&#x27; width=&#x27;100%25&#x27; height=&#x27;100%25&#x27;/%3E%3CfeComposite
+        operator=&#x27;out&#x27; in=&#x27;s&#x27;/%3E%3CfeComposite in2=&#x27;SourceGraphic&#x27;/%3E%3CfeGaussianBlur
+        stdDeviation=&#x27;20&#x27;/%3E%3C/filter%3E%3Cimage width=&#x27;100%25&#x27;
+        height=&#x27;100%25&#x27; x=&#x27;0&#x27; y=&#x27;0&#x27; preserveAspectRatio=&#x27;none&#x27;
+        style=&#x27;filter: url(%23b);&#x27; href=&#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wcAAwAB/ucNC4UAAAAASUVORK5CYII=&#x27;/%3E%3C/svg%3E&quot;)\"
+        srcSet=\"https://cdn.sanity.io/images/w77i7m8x/production/c47871628e0abd711d3b18acf850972fff8c7d1c-27x38.svg?w=32&amp;q=75&amp;fit=clip&amp;auto=format
+        1x, https://cdn.sanity.io/images/w77i7m8x/production/c47871628e0abd711d3b18acf850972fff8c7d1c-27x38.svg?w=64&amp;q=75&amp;fit=clip&amp;auto=format
+        2x\" src=\"https://cdn.sanity.io/images/w77i7m8x/production/c47871628e0abd711d3b18acf850972fff8c7d1c-27x38.svg?w=64&amp;q=75&amp;fit=clip&amp;auto=format\"/><div
+        class=\"t-52 font-medium text-white\">404</div></div></div><div class=\"text-left
+        mx-0\"><h2 class=\"t-80 text-white mb-4 md:mb-2.5\" style=\"max-width:595px\">Network
+        (dis)connected</h2><div class=\"t-b18 text-white/70 mb-5 lg:mb-9\" style=\"max-width:499px\"><div
+        class=\"content-prose\"><p>Don\u2019t worry, you haven\u2019t broken anything.
+        This page has simply disappeared into thin air. Head back to our homepage,
+        and start again.</p></div></div><div class=\"w-full xs:w-auto flex justify-start\"><div
+        class=\"flex w-full  flex-col gap-y-4 xs:w-auto xs:flex-row xs:items-center
+        xs:space-x-5 md:space-x-[30px]\"><a target=\"\" data-track=\"Link Clicked\"
+        data-track-properties=\"{&quot;label&quot;: &quot;Take me back&quot;}\" href=\"/\"><div
+        class=\"inline-flex shrink-0 border transition-colors duration-200 w-full
+        xs:w-auto items-center justify-center text-center relative focus:outline-none
+        group transition-all overflow-hidden font-body font-medium rounded-lg group
+        gap-[11px] py-2 px-[17px] leading-[1.46] tracking-[-0.16px] bg-heading-white
+        border-white text-heading-black hover:bg-gray-50 hover:border-gray-50\"><div>Take
+        me back</div><div class=\"relative \"><span class=\"block will-change-transform\"
+        style=\"opacity:1;transform:none\"><svg xmlns=\"http://www.w3.org/2000/svg\"
+        viewBox=\"0 0 16 18\" class=\"w-4\"><use href=\"/sprite.svg#arrowRight\"></use></svg></span><span
+        class=\"absolute inset-0 block will-change-transform\" style=\"opacity:0;transform:translateX(-15px)
+        translateY(0px) translateZ(0)\"><svg xmlns=\"http://www.w3.org/2000/svg\"
+        viewBox=\"0 0 16 18\" class=\"w-4\"><use href=\"/sprite.svg#arrowRight\"></use></svg></span></div></div></a></div></div></div></div><div
+        class=\"mt-6 w-full max-w-[730px] shrink-0 md:mt-0 laptop:w-[593px]\"><img
+        _type=\"asset\" video=\"[object Object]\" alt=\"404\" loading=\"lazy\" width=\"730\"
+        height=\"730\" decoding=\"async\" data-nimg=\"1\" class=\"md:block mx-auto\"
+        style=\"color:transparent;background-size:cover;background-position:50% 50%;background-repeat:no-repeat;background-image:url(&quot;data:image/svg+xml;charset=utf-8,%3Csvg
+        xmlns=&#x27;http://www.w3.org/2000/svg&#x27; viewBox=&#x27;0 0 730 730&#x27;%3E%3Cfilter
+        id=&#x27;b&#x27; color-interpolation-filters=&#x27;sRGB&#x27;%3E%3CfeGaussianBlur
+        stdDeviation=&#x27;20&#x27;/%3E%3CfeColorMatrix values=&#x27;1 0 0 0 0 0 1
+        0 0 0 0 0 1 0 0 0 0 0 100 -1&#x27; result=&#x27;s&#x27;/%3E%3CfeFlood x=&#x27;0&#x27;
+        y=&#x27;0&#x27; width=&#x27;100%25&#x27; height=&#x27;100%25&#x27;/%3E%3CfeComposite
+        operator=&#x27;out&#x27; in=&#x27;s&#x27;/%3E%3CfeComposite in2=&#x27;SourceGraphic&#x27;/%3E%3CfeGaussianBlur
+        stdDeviation=&#x27;20&#x27;/%3E%3C/filter%3E%3Cimage width=&#x27;100%25&#x27;
+        height=&#x27;100%25&#x27; x=&#x27;0&#x27; y=&#x27;0&#x27; preserveAspectRatio=&#x27;none&#x27;
+        style=&#x27;filter: url(%23b);&#x27; href=&#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wcAAwAB/ucNC4UAAAAASUVORK5CYII=&#x27;/%3E%3C/svg%3E&quot;)\"
+        srcSet=\"https://cdn.sanity.io/images/w77i7m8x/production/00314739bf834a0d9e0a67cd383f295181584c64-730x730.svg?w=750&amp;q=75&amp;fit=clip&amp;auto=format
+        1x, https://cdn.sanity.io/images/w77i7m8x/production/00314739bf834a0d9e0a67cd383f295181584c64-730x730.svg?w=1920&amp;q=75&amp;fit=clip&amp;auto=format
+        2x\" src=\"https://cdn.sanity.io/images/w77i7m8x/production/00314739bf834a0d9e0a67cd383f295181584c64-730x730.svg?w=1920&amp;q=75&amp;fit=clip&amp;auto=format\"/></div></div></div></main><footer
+        class=\"mt-16 bg-white py-12\"><div class=\"mx-auto w-full max-w-[1360px]
+        px-6 md:max-w-[1440px] md:px-16\"><div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2
+        md:grid-cols-12\"><div class=\"px-3 sm:col-span-2 md:col-span-4 md:px-8 md:py-8\"><a
+        class=\"block w-[110px]\" title=\"Homepage\" href=\"/\"><svg width=\"48\"
+        height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"
+        aria-hidden=\"true\"><path d=\"M3 15C4.65685 15 6 13.6569 6 12C6 10.3431 4.65685
+        9 3 9C1.34315 9 0 10.3431 0 12C0 13.6569 1.34315 15 3 15Z\" fill=\"currentColor\"></path><path
+        d=\"M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9
+        9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z\" fill=\"currentColor\"></path><path
+        d=\"M12 24C13.6569 24 15 22.6569 15 21C15 19.3431 13.6569 18 12 18C10.3431
+        18 9 19.3431 9 21C9 22.6569 10.3431 24 12 24Z\" fill=\"currentColor\"></path><path
+        d=\"M21 15C22.6569 15 24 13.6569 24 12C24 10.3431 22.6569 9 21 9C19.3431 9
+        18 10.3431 18 12C18 13.6569 19.3431 15 21 15Z\" fill=\"currentColor\"></path><path
+        d=\"M3 24C4.65685 24 6 22.6569 6 21C6 19.3431 4.65685 18 3 18C1.34315 18 0
+        19.3431 0 21C0 22.6569 1.34315 24 3 24Z\" fill=\"currentColor\" fill-opacity=\"0.4\"></path><path
+        d=\"M21 24C22.6569 24 24 22.6569 24 21C24 19.3431 22.6569 18 21 18C19.3431
+        18 18 19.3431 18 21C18 22.6569 19.3431 24 21 24Z\" fill=\"currentColor\" fill-opacity=\"0.4\"></path><path
+        d=\"M3 6C4.65685 6 6 4.65685 6 3C6 1.34315 4.65685 0 3 0C1.34315 0 0 1.34315
+        0 3C0 4.65685 1.34315 6 3 6Z\" fill=\"currentColor\" fill-opacity=\"0.4\"></path><path
+        d=\"M12 6C13.6569 6 15 4.65685 15 3C15 1.34315 13.6569 0 12 0C10.3431 0 9
+        1.34315 9 3C9 4.65685 10.3431 6 12 6Z\" fill=\"currentColor\" fill-opacity=\"0.4\"></path><path
+        d=\"M21 6C22.6569 6 24 4.65685 24 3C24 1.34315 22.6569 0 21 0C19.3431 0 18
+        1.34315 18 3C18 4.65685 19.3431 6 21 6Z\" fill=\"currentColor\" fill-opacity=\"0.4\"></path></svg></a></div><div
+        class=\"py-3 sm:col-span-1 md:col-span-2 md:py-8\"><h3 class=\"flex flex-row
+        items-center gap-2.5 px-3 pb-3 font-mdio text-xs font-medium uppercase !tracking-[0.6px]
+        text-gray-700/80\"><span class=\"shrink-0\">Company</span><hr class=\"flex-1
+        border-gray-200\"/></h3><ul class=\"flex flex-col gap-1\"><li class=\"rounded-md
+        p-3 transition-colors duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px]
+        items-center text-sm font-medium text-gray-700 no-underline\" href=\"/company\">About
+        Tailscale</a></li><li class=\"rounded-md p-3 transition-colors duration-200
+        hover:bg-gray-200\"><a class=\"flex h-[20px] items-center text-sm font-medium
+        text-gray-700 no-underline\" href=\"/careers\">Careers</a></li><li class=\"rounded-md
+        p-3 transition-colors duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px]
+        items-center text-sm font-medium text-gray-700 no-underline\" href=\"/press\">Press</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"/opensource\">Open Source</a></li></ul></div><div class=\"py-3 sm:col-span-1
+        md:col-span-2 md:py-8\"><h3 class=\"flex flex-row items-center gap-2.5 px-3
+        pb-3 font-mdio text-xs font-medium uppercase !tracking-[0.6px] text-gray-700/80\"><span
+        class=\"shrink-0\">Help &amp; Support</span><hr class=\"flex-1 border-gray-200\"/></h3><ul
+        class=\"flex flex-col gap-1\"><li class=\"rounded-md p-3 transition-colors
+        duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px] items-center text-sm
+        font-medium text-gray-700 no-underline\" href=\"/support\">Support</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"/sales\">Sales</a></li><li class=\"rounded-md p-3 transition-colors
+        duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px] items-center text-sm
+        font-medium text-gray-700 no-underline\" href=\"/partnerships\">Partnerships</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"/security\">Security</a></li><li class=\"rounded-md p-3 transition-colors
+        duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px] items-center text-sm
+        font-medium text-gray-700 no-underline\" href=\"/changelog\">Changelog</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        target=\"_blank\" rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center
+        text-sm font-medium text-gray-700 no-underline\" href=\"https://status.tailscale.com\">Tailscale
+        Status</a></li></ul></div><div class=\"py-3 sm:col-span-1 md:col-span-2 md:py-8\"><h3
+        class=\"flex flex-row items-center gap-2.5 px-3 pb-3 font-mdio text-xs font-medium
+        uppercase !tracking-[0.6px] text-gray-700/80\"><span class=\"shrink-0\">Legal</span><hr
+        class=\"flex-1 border-gray-200\"/></h3><ul class=\"flex flex-col gap-1\"><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"/terms\">Terms of Service</a></li><li class=\"rounded-md p-3 transition-colors
+        duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px] items-center text-sm
+        font-medium text-gray-700 no-underline\" href=\"/privacy\">Privacy Policy</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"/privacy-policy#california-notice\">California Notice</a></li><li class=\"rounded-md
+        p-3 transition-colors duration-200 hover:bg-gray-200\"><a class=\"flex h-[20px]
+        items-center text-sm font-medium text-gray-700 no-underline\" href=\"/cookie-notice\">Cookie
+        Notice</a></li><li class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><button
+        type=\"button\" class=\"flex h-[20px] items-center gap-2 text-left text-sm
+        font-medium text-gray-700\">Your privacy choices<img alt=\"Check mark and
+        x on a white and blue pill button\" loading=\"lazy\" width=\"30\" height=\"14\"
+        decoding=\"async\" data-nimg=\"1\" style=\"color:transparent\" src=\"https://cdn.sanity.io/images/w77i7m8x/production/07d853f507039b2489d9818cb6ee7442c1b60e2a-30x14.svg\"/></button></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"/legal\">All Legal</a></li></ul></div><div class=\"py-3 sm:col-span-1
+        md:col-span-2 md:py-8\"><h3 class=\"flex flex-row items-center gap-2.5 px-3
+        pb-3 font-mdio text-xs font-medium uppercase !tracking-[0.6px] text-gray-700/80\"><span
+        class=\"shrink-0\">Social</span><hr class=\"flex-1 border-gray-200\"/></h3><ul
+        class=\"flex flex-col gap-1\"><li class=\"rounded-md p-3 transition-colors
+        duration-200 hover:bg-gray-200\"><a target=\"_blank\" rel=\"noopener noreferrer\"
+        class=\"flex h-[20px] items-center text-sm font-medium text-gray-700 no-underline\"
+        href=\"https://discord.gg/tailscale\">Discord</a></li><li class=\"rounded-md
+        p-3 transition-colors duration-200 hover:bg-gray-200\"><a target=\"_blank\"
+        rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center text-sm font-medium
+        text-gray-700 no-underline\" href=\"https://github.com/tailscale\">GitHub</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        target=\"_blank\" rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center
+        text-sm font-medium text-gray-700 no-underline\" href=\"https://www.linkedin.com/company/tailscale\">LinkedIn</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        target=\"_blank\" rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center
+        text-sm font-medium text-gray-700 no-underline\" href=\"https://hachyderm.io/@tailscale\">Mastodon</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        target=\"_blank\" rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center
+        text-sm font-medium text-gray-700 no-underline\" href=\"https://www.reddit.com/r/Tailscale\">Reddit</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        target=\"_blank\" rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center
+        text-sm font-medium text-gray-700 no-underline\" href=\"https://www.youtube.com/@Tailscale\">YouTube</a></li><li
+        class=\"rounded-md p-3 transition-colors duration-200 hover:bg-gray-200\"><a
+        target=\"_blank\" rel=\"noopener noreferrer\" class=\"flex h-[20px] items-center
+        text-sm font-medium text-gray-700 no-underline\" href=\"https://twitter.com/tailscale\">X
+        (Twitter)</a></li></ul></div></div><div class=\"mx-3 flex flex-col items-start
+        gap-3 border-gray-200 sm:border-t sm:pt-6 md:mx-8 md:flex-row md:items-center
+        md:border-t-0 md:pt-0\"><span class=\"text-xs text-gray-500\">\xA9 2026 Tailscale
+        Inc.</span><hr class=\"hidden flex-1 self-center border-gray-200 md:inline\"/><span
+        class=\"flex flex-col text-xs text-gray-500 md:block\"><span>Tailscale is
+        a registered trademark of Tailscale Inc.</span><span class=\"hidden md:inline\">
+        | </span><span>WireGuard is a registered trademark of Jason A. Donenfeld</span></span></div></div></footer></div><script
+        id=\"__NEXT_DATA__\" type=\"application/json\">{\"props\":{\"pageProps\":{\"page\":{\"_id\":\"747a1d74-fd7c-43c3-83f5-ae55218823dd\",\"_type\":\"page\",\"cta\":null,\"ctaColor\":\"red\",\"footerStyle\":\"light\",\"headerStyle\":\"light\",\"invertHeader\":null,\"overwriteCTAColor\":true,\"parent\":null,\"removeCTA\":true,\"removeFooter\":null,\"removeHeader\":false,\"sections\":[{\"_type\":\"landingPage\",\"landingPageLayout\":\"error\",\"error\":{\"_type\":\"errorLandingPage\",\"asset\":{\"_type\":\"asset\",\"borderRadius\":\"none\",\"image\":{\"_type\":\"sanityImage\",\"alt\":\"404\",\"asset\":{\"_ref\":\"image-00314739bf834a0d9e0a67cd383f295181584c64-730x730-svg\",\"_type\":\"reference\"}},\"type\":\"image\",\"video\":{\"clickType\":\"watchVideoCaption\",\"mobileStaticAlt\":{\"_type\":\"asset\",\"type\":\"image\",\"video\":{\"clickType\":\"watchVideoCaption\",\"mobileStaticAlt\":{\"_type\":\"asset\",\"type\":\"image\",\"video\":{\"clickType\":\"watchVideoCaption\",\"mobileStaticAlt\":{\"_type\":\"asset\",\"type\":\"image\"},\"playType\":\"click\",\"useMobileStaticAlt\":false}},\"playType\":\"click\",\"useMobileStaticAlt\":false}},\"playType\":\"click\",\"useMobileStaticAlt\":false}},\"label\":{\"icon\":{\"_type\":\"sanityImage\",\"alt\":\"404
+        icon\",\"asset\":{\"_ref\":\"image-c47871628e0abd711d3b18acf850972fff8c7d1c-27x38-svg\",\"_type\":\"reference\"}},\"text\":\"404\"},\"textCard\":{\"_type\":\"textCard\",\"heading\":\"Network
+        (dis)connected\",\"links\":[{\"_key\":\"66dc38668193\",\"button\":{\"_type\":\"button\",\"buttonOptions\":{\"addArrow\":true,\"color\":\"white\"},\"link\":{\"title\":\"Take
+        me back\",\"url\":\"/\"}},\"textLink\":{\"_type\":\"textLink\",\"textLinkOptions\":{\"arrowColor\":\"black\",\"underlineColor\":\"black\"}},\"type\":\"button\"}],\"options\":{\"addSubheading\":false,\"animateOffset\":false,\"contentFontColor\":\"white70\",\"contentFontSize\":\"b18\",\"contentMarginBottom\":\"36\",\"contentMaxWidth\":499,\"hasMobileTextAlignment\":false,\"headingFontColor\":\"white\",\"headingFontSize\":\"80\",\"headingMarginBottom\":\"10\",\"headingMaxWidth\":595,\"headingTag\":\"h2\",\"highlightColor\":\"black\",\"subheadingColor\":\"white\",\"subheadingFontSize\":\"subheading\",\"subheadingMarginBottom\":\"16\",\"subheadingTag\":\"h1\"},\"richContent\":[{\"_key\":\"d980627ead4b\",\"_type\":\"block\",\"children\":[{\"_key\":\"005243496bc10\",\"_type\":\"span\",\"marks\":[],\"text\":\"Don\u2019t
+        worry, you haven\u2019t broken anything. This page has simply disappeared
+        into thin air. Head back to our homepage, and start again.\"}],\"markDefs\":[],\"style\":\"normal\"}]},\"title\":\"404\"}}],\"seo\":{\"indexable\":true,\"seoTitle\":\"404\"},\"slug\":{\"_type\":\"slug\",\"current\":\"404\"},\"themeColor\":null,\"title\":\"404\"},\"global\":{\"announcement\":{\"link\":{\"label\":\"Read
+        the announcement to see what it means for you. \u2192\",\"url\":\"https://tailscale.com/blog/border0-joins-tailscale/?utm_source=announcement-bar\\u0026utm_medium=content\\u0026utm_campaign=border0-announcement\"},\"text\":\"Border0
+        has joined Tailscale!\"},\"footer\":{\"_createdAt\":\"2023-10-06T14:44:29Z\",\"_id\":\"422b4abf-6e3f-4213-ab94-a03dd444be3d\",\"_rev\":\"cvyAZxF5iE3rKFZlZADQj6\",\"_system\":{\"base\":{\"id\":\"422b4abf-6e3f-4213-ab94-a03dd444be3d\",\"rev\":\"QO1lT9vtV5kYGc8zKtne7R\"}},\"_type\":\"footer\",\"_updatedAt\":\"2025-11-12T18:00:18Z\",\"copyrightContent\":\"Tailscale
+        Inc. All rights reserved. Tailscale is a registered trademark of Tailscale
+        Inc.\",\"cta\":{\"asset\":{\"_type\":\"asset\",\"image\":{\"_type\":\"sanityImage\",\"alt\":\"cta
+        phone\",\"asset\":{\"_ref\":\"image-b715b4ca5e2577da60f0d529a4a9bc2ad4cadf59-362x567-svg\",\"_type\":\"reference\"}},\"type\":\"image\"},\"ctaButton\":{\"_type\":\"button\",\"buttonOptions\":{\"color\":\"white\"},\"link\":{\"title\":\"Get
+        started\",\"url\":\"/get-started\"}},\"darkLogoGrid\":[{\"_key\":\"fb360d1bc6c4\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"mercury\",\"asset\":{\"_ref\":\"image-a1fb7441ec6ea5254d0f14119dbe0abf5c822f9f-199x81-svg\",\"_type\":\"reference\"}}},{\"_key\":\"a24139987731\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"instacart\",\"asset\":{\"_ref\":\"image-62410277e3cd5df52c9b59e787ae52a5a2699580-199x81-svg\",\"_type\":\"reference\"}}},{\"_key\":\"0fa57e2eebee\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"Retool\",\"asset\":{\"_ref\":\"image-80654c9d97220caec3e35ba29d3e7439a03d482a-199x82-svg\",\"_type\":\"reference\"}}},{\"_key\":\"b47251ca28bd\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"duolingo\",\"asset\":{\"_ref\":\"image-9b799915a326b1b78decc95e6ce251b87111f2bf-199x81-svg\",\"_type\":\"reference\"}}},{\"_key\":\"7bf06e2e5305\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"Hugging
+        Face\",\"asset\":{\"_ref\":\"image-b36780abd0594e34b52e74176a6b61811bbed602-199x82-svg\",\"_type\":\"reference\"}}}],\"heading\":\"Try
+        Tailscale for |free|\",\"logoGrid\":[{\"_key\":\"a3a9b2012378\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"mercury\",\"asset\":{\"_ref\":\"image-459a7a8492910eeb22f22bb8d4c0f864b0bae25f-199x81-svg\",\"_type\":\"reference\"}}},{\"_key\":\"993b75d39e13\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"instacrt\",\"asset\":{\"_ref\":\"image-7d127f4bb62a408b056328349f291857df6251b3-199x81-svg\",\"_type\":\"reference\"}}},{\"_key\":\"8449f10eb5c7\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"Retool\",\"asset\":{\"_ref\":\"image-e9579b00087d7896e9cb750f4eb39f2c11ed11b8-199x82-svg\",\"_type\":\"reference\"}}},{\"_key\":\"3ab303288a39\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"duolingo\",\"asset\":{\"_ref\":\"image-7958bf3d43a30e661ca74cf0510f250d9b99ecef-199x81-svg\",\"_type\":\"reference\"}}},{\"_key\":\"5e630c781c8a\",\"logo\":{\"_type\":\"sanityImage\",\"alt\":\"Hugging
+        Face\",\"asset\":{\"_ref\":\"image-68e2e5024898bcd6f6d142e0306dc7564787e1d7-199x82-svg\",\"_type\":\"reference\"}}}],\"secondaryCta\":{\"heading\":\"Schedule
+        a demo\",\"link\":{\"title\":\"Contact sales\",\"url\":\"/contact/sales\"}},\"textCard\":{\"_type\":\"textCard\",\"heading\":\"Try
+        Tailscale for |free|\",\"links\":[{\"_key\":\"dc04d805f7e0\",\"button\":{\"_type\":\"button\",\"buttonOptions\":{\"color\":\"white\"},\"link\":{\"title\":\"Get
+        started\",\"url\":\"https://login.tailscale.com/start\"}},\"textLink\":{\"_type\":\"textLink\",\"textLinkOptions\":{\"arrowColor\":\"black\",\"underlineColor\":\"black\"}},\"type\":\"button\"}],\"options\":{\"contentFontColor\":\"white\",\"hasMobileTextAlignment\":false,\"headingFontColor\":\"white\",\"headingFontSize\":\"h3\",\"headingMarginBottom\":\"30\",\"headingMaxWidth\":292,\"highlightColor\":\"blue-3\",\"sectionAlignment\":\"left\"}}},\"footerNav\":[{\"_key\":\"05f3fa61c972\",\"heading\":\"Product\",\"links\":[{\"_key\":\"30386cf08177\",\"title\":\"How
+        it works\",\"url\":\"/blog/how-tailscale-works/\"},{\"_key\":\"45dec9531713\",\"title\":\"Pricing\",\"url\":\"/pricing\"},{\"_key\":\"e6f4d8daff21\",\"title\":\"Integrations\",\"url\":\"/integrations\"},{\"_key\":\"d4f7875a767f\",\"title\":\"Features\",\"url\":\"/features\"},{\"_key\":\"64846fcdaf3b\",\"title\":\"Compare
+        Tailscale\",\"url\":\"/compare\"}]},{\"_key\":\"7870d03d9802\",\"heading\":\"Use
+        Cases\",\"links\":[{\"_key\":\"7b4858603fc7\",\"title\":\"Business VPN\",\"url\":\"/use-cases/business-vpn\"},{\"_key\":\"06fbf46e9354\",\"title\":\"CI/CD\",\"url\":\"/use-cases/ci-cd\"},{\"_key\":\"602f747f5b2a\",\"title\":\"Infra
+        Access\",\"url\":\"/use-cases/infrastructure-access\"},{\"_key\":\"8660f39ec574\",\"title\":\"Cloud
+        Connectivity\",\"url\":\"/use-cases/cloud-connectivity\"},{\"_key\":\"ab3e69241df2\",\"title\":\"Zero
+        Trust Networking\",\"url\":\"/use-cases/zero-trust-networking\"},{\"_key\":\"b79f544a8266\",\"title\":\"Homelab\",\"url\":\"/use-cases/homelab\"}]},{\"_key\":\"2e262725243d\",\"heading\":\"Resources\",\"links\":[{\"_key\":\"b5ad8866742c\",\"title\":\"Blog\",\"url\":\"/blog\"},{\"_key\":\"21869f26f11b\",\"title\":\"Events
+        \\u0026 Webinars\",\"url\":\"/events-webinars\"},{\"_key\":\"c844ea072844\",\"title\":\"Partnerships\",\"url\":\"/partnerships\"}]},{\"_key\":\"a1e16018d519\",\"heading\":\"Company\",\"links\":[{\"_key\":\"8cc3fedb5b31\",\"title\":\"Company\",\"url\":\"/company\"},{\"_key\":\"e69d139c2c7c\",\"title\":\"Careers\",\"url\":\"/careers\"},{\"_key\":\"ad370d7ab2c1\",\"title\":\"Press\",\"url\":\"/press\"}]},{\"_key\":\"b25bd2c7203e\",\"heading\":\"Help
+        \\u0026 Support\",\"links\":[{\"_key\":\"f7d6ef6a99c6\",\"title\":\"Support\",\"url\":\"/contact/support\"},{\"_key\":\"18077954da8f455140153a58c74e53ba\",\"title\":\"Sales\",\"url\":\"/contact/sales\"},{\"_key\":\"3b91a6bb3d6b\",\"title\":\"Security\",\"url\":\"/security\"},{\"_key\":\"9d3e837341e2\",\"title\":\"Legal\",\"url\":\"/legal\"},{\"_key\":\"a69304fe5b80\",\"title\":\"Open
+        Source\",\"url\":\"/opensource\"},{\"_key\":\"a02943ca7fdd\",\"title\":\"Changelog\",\"url\":\"/changelog\"},{\"_key\":\"94a676559b98\",\"title\":\"Tailscale
+        Status\",\"url\":\"https://status.tailscale.com/\"}]},{\"_key\":\"0bdaf34fbe61\",\"heading\":\"Learn\",\"links\":[{\"_key\":\"6c45141fcc65\",\"title\":\"SSH
+        keys\",\"url\":\"/learn/generate-ssh-keys/\"},{\"_key\":\"86c070f995c4\",\"title\":\"Docker
+        SSH\",\"url\":\"/learn/ssh-into-docker-container/\"},{\"_key\":\"22e6d051e763\",\"title\":\"NAT
+        Traversal\",\"url\":\"/blog/how-nat-traversal-works/\"},{\"_key\":\"4e51a8a4f0a7\",\"title\":\"MagicDNS\",\"url\":\"/blog/2021-09-private-dns-with-magicdns/\"},{\"_key\":\"f8f8893085b3\",\"title\":\"PAM\",\"url\":\"/learn/privileged-access-management/\"},{\"_key\":\"e7fdb19bd312\",\"title\":\"All
+        articles\",\"url\":\"/learn\"}]}],\"legalContent\":\"WireGuard is a registered
+        trademark of Jason A. Donenfeld.\",\"legalNav\":[{\"_key\":\"b3b1d8dfddea\",\"title\":\"Terms
+        of Service\",\"url\":\"/terms\"},{\"_key\":\"3e22b7802445\",\"title\":\"Privacy
+        Policy\",\"url\":\"/privacy-policy\"},{\"_key\":\"78a1108d49e9\",\"title\":\"California
+        Notice\",\"url\":\"https://tailscale.com/privacy-policy#california-notice\"},{\"_key\":\"9d3370545d40\",\"title\":\"Cookie
+        Notice\",\"url\":\"https://tailscale.com/cookie-notice\"}],\"title\":\"Production
+        Footer\"},\"globalOptions\":null,\"header\":{\"_createdAt\":\"2023-10-06T12:21:23Z\",\"_id\":\"7797109d-2dc4-4a75-b5a3-b1019c33212f\",\"_rev\":\"j2fyDG1GUVWvNQkvjTn5zS\",\"_system\":{\"base\":{\"id\":\"7797109d-2dc4-4a75-b5a3-b1019c33212f\",\"rev\":\"5FsRtrxmPymeiFerrOYlEk\"}},\"_type\":\"header\",\"_updatedAt\":\"2026-02-02T22:44:03Z\",\"button\":{\"_type\":\"button\",\"buttonOptions\":{\"color\":\"black\"},\"link\":{\"title\":\"Get
+        started - it's free!\",\"url\":\"https://login.tailscale.com/start\"}},\"links\":[{\"_key\":\"157b4ad1150d\",\"title\":\"Download\",\"url\":\"/download\"},{\"_key\":\"f00209e74f6b\",\"title\":\"Log
+        in\",\"url\":\"https://login.tailscale.com/welcome\"}],\"menu\":[{\"_key\":\"95381f81d527\",\"hasSubmenu\":true,\"submenu\":{\"product\":{\"leftCol\":{\"topNav\":{\"heading\":\"Meet
+        Tailscale\",\"links\":[{\"_key\":\"5495d201056a\",\"icon\":{\"_type\":\"sanityImage\",\"alt\":\"icon\"},\"link\":\"/blog/how-tailscale-works/\",\"title\":\"How
+        it works\"},{\"_key\":\"dc9cde7ff83cb94cfc98ff29bdcd0997\",\"icon\":{\"_type\":\"sanityImage\",\"alt\":\"icon\"},\"link\":\"/why-tailscale\",\"title\":\"Why
+        Tailscale\"},{\"_key\":\"5d88e3ffcc6b\",\"icon\":{\"_type\":\"sanityImage\",\"alt\":\"WireGuard\xAE\"},\"link\":\"/wireguard-vpn\",\"title\":\"WireGuard\xAE
+        for Enterprises\"},{\"_key\":\"435de37ddd5f\",\"icon\":{\"_type\":\"sanityImage\",\"alt\":\"Bring
+        Tailscale to Work\"},\"link\":\"/bring-tailscale-to-work\",\"title\":\"Bring
+        Tailscale to Work\"}]}},\"rightCol\":{\"nav\":{\"heading\":\"Explore\",\"links\":[{\"_key\":\"c653da519dfb\",\"link\":\"/integrations\",\"title\":\"Integrations\"},{\"_key\":\"a878da5fa54c\",\"link\":\"/features\",\"title\":\"Features\"},{\"_key\":\"adda698ed879\",\"link\":\"/compare\",\"title\":\"Compare
+        Tailscale\"},{\"_key\":\"3341bd9805df\",\"link\":\"/community/community-projects\",\"title\":\"Community
+        Projects\"},{\"_key\":\"b57369965809\",\"link\":\"/partnerships\",\"title\":\"Partnerships\"}]}}},\"submenuType\":\"product\"},\"title\":\"Product\"},{\"_key\":\"a7062f1924df\",\"hasSubmenu\":true,\"submenu\":{\"product\":{\"leftCol\":{\"topNav\":{\"heading\":\"By
+        use-case\",\"links\":[{\"_key\":\"6fc65e9fe1c6\",\"link\":\"/use-cases/business-vpn\",\"title\":\"Business
+        VPN\"},{\"_key\":\"193eaaa0cef8\",\"link\":\"/use-cases/ci-cd\",\"title\":\"CI/CD\"},{\"_key\":\"c59997229dde\",\"link\":\"/use-cases/infrastructure-access\",\"title\":\"Infra
+        Access\"},{\"_key\":\"05cadfcf3e65b04708a9d88060f68f9e\",\"link\":\"/use-cases/cloud-connectivity\",\"title\":\"Cloud
+        Connectivity\"},{\"_key\":\"6a363d694952\",\"link\":\"/use-cases/zero-trust-networking\",\"title\":\"Zero
+        Trust Networking\"},{\"_key\":\"d99d14013ab3\",\"link\":\"/use-cases/homelab\",\"title\":\"Homelab\"},{\"_key\":\"b049143e7a1c\",\"link\":\"/use-cases/securing-ai\",\"title\":\"Securing
+        AI\"}]}},\"rightCol\":{\"nav\":{\"heading\":\"By role\",\"links\":[{\"_key\":\"502a00f49baf\",\"link\":\"/solutions/devops\",\"title\":\"DevOps\"},{\"_key\":\"0fe4c0d6fa83\",\"link\":\"/solutions/it\",\"title\":\"IT\"},{\"_key\":\"026f30b876a7\",\"link\":\"/solutions/security\",\"title\":\"Security\"}]}}},\"submenuType\":\"product\"},\"title\":\"Solutions\"},{\"_key\":\"fd055b16290df04c6012d0d33c2fad13\",\"hasSubmenu\":false,\"link\":\"/enterprise\",\"submenu\":{\"submenuType\":\"product\"},\"title\":\"Enterprise\"},{\"_key\":\"b595975539c7407a7ed4510edd549223\",\"hasSubmenu\":false,\"link\":\"/customers\",\"submenu\":{\"product\":{\"leftCol\":{\"topNav\":{\"heading\":\"Nav
+        heading here\",\"links\":[{\"_key\":\"2d22491d8262\",\"description\":\"How
+        Cribl Enables Secure Work From Anywhere with Tailscale\",\"icon\":{\"_type\":\"sanityImage\",\"alt\":\"Alt
+        text \",\"asset\":{\"_ref\":\"image-a06dc612b1e3e4f4df53a72030002600639a8738-300x120-png\",\"_type\":\"reference\"}},\"link\":\"https://tailscale.com/customers\",\"title\":\"Title
+        here\"}]}}},\"resources\":{\"topNav\":[{\"_key\":\"61d0f0cb130e\",\"description\":\"How
+        Cribl Enables Secure Work From Anywhere with Tailscale\",\"heading\":\"Cribl\"},{\"_key\":\"712684d509a6a6ea07ab9401bdb23f8f\",\"description\":\"How
+        Cribl Enables Secure Work From Anywhere with Tailscale\",\"heading\":\"Cribl\"},{\"_key\":\"ceac3f234a3a6923a671af91772b7e8b\",\"description\":\"How
+        Cribl Enables Secure Work From Anywhere with Tailscale\",\"heading\":\"Cribl\"}]},\"submenuType\":\"product\"},\"title\":\"Customers\"},{\"_key\":\"f06fabeb084c\",\"hasSubmenu\":false,\"link\":\"/docs\",\"submenu\":{\"submenuType\":\"product\"},\"title\":\"Docs\"},{\"_key\":\"f2537b6fa068\",\"hasSubmenu\":false,\"link\":\"/blog\",\"submenu\":{\"submenuType\":\"product\"},\"title\":\"Blog\"},{\"_key\":\"e1b7b44dc091\",\"hasSubmenu\":false,\"link\":\"/pricing\",\"submenu\":{\"submenuType\":\"product\"},\"title\":\"Pricing\"}],\"title\":\"Production
+        Header\"},\"legal\":null,\"newsBar\":null,\"redirects\":[{\"_key\":\"8b0a3ebcf822\",\"destination\":\"/wireguard-vpn\",\"source\":\"/wireguard\"}],\"seo\":{\"ogImage\":{\"_type\":\"image\",\"asset\":{\"_ref\":\"image-8e0455b2d9b33c6151016afdf2ea81d7623c2f04-1200x628-png\",\"_type\":\"reference\"}}},\"socials\":null,\"newHeader\":{\"links\":[{\"feature\":{\"buttons\":[{\"_key\":\"eda43f90569a\",\"_type\":\"buttonsMember\",\"openInNewTab\":false,\"text\":\"Click
+        here\",\"url\":\"https://tailscale.com/use-cases/securing-ai\"}],\"contentText\":\"Unified
+        AI governance for AI agents and users.\",\"image\":{\"alt\":\"aperture dashboard\",\"asset\":{\"_createdAt\":\"2026-03-18T00:32:42Z\",\"_id\":\"image-7fbf14ac75bdf258eeff9efb2a2d5bbbf2e87098-266x342-svg\",\"_rev\":\"9SdknGxd6abfl1HH8tyFpw\",\"_type\":\"sanity.imageAsset\",\"_updatedAt\":\"2026-03-18T00:32:42Z\",\"assetId\":\"7fbf14ac75bdf258eeff9efb2a2d5bbbf2e87098\",\"extension\":\"svg\",\"metadata\":{\"_type\":\"sanity.imageMetadata\",\"blurHash\":\"d,Ju4Lxuxuxut7RkWBay~qRjRjWBM{ofofj[xuoJaeWB\",\"dimensions\":{\"_type\":\"sanity.imageDimensions\",\"aspectRatio\":0.7777777777777778,\"height\":342,\"width\":266},\"hasAlpha\":true,\"isOpaque\":true,\"lqip\":\"data:image/jpeg;base64,/9j/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAaABQDASIAAhEBAxEB/8QAGQAAAwADAAAAAAAAAAAAAAAAAAcIAgUG/8QAKRAAAQMCBQIGAwAAAAAAAAAAAQACAwUGBAcREiExUxUiVXGRkyNzkv/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/EABkRAQEAAwEAAAAAAAAAAAAAAAABAhExEv/aAAwDAQACEQMRAD8AZVWuy3qViJIMZNGyWMgObpyNVtoavbErA7xintBGvMgU751fjvuoNeCBo3gcHol/odu7z6e61l5vITc6sw1O2PWqb9gQoz2uPI36e6FldnlnFlrdFfvbG46kU4T4WQN2v3gdAuIOTl+Bm00dmn7AqrEsncf8lZGWTuP/AKKglA5O336S37AhVYZZO4/5KEH/2Q==\",\"palette\":{\"_type\":\"sanity.imagePalette\",\"darkMuted\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#2f3651\",\"foreground\":\"#fff\",\"population\":0.27,\"title\":\"#fff\"},\"darkVibrant\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#2a386e\",\"foreground\":\"#fff\",\"population\":0.57,\"title\":\"#fff\"},\"dominant\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#6490e7\",\"foreground\":\"#fff\",\"population\":1.21,\"title\":\"#fff\"},\"lightMuted\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#dad1c4\",\"foreground\":\"#000\",\"population\":0.02,\"title\":\"#000\"},\"lightVibrant\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#d3d9f1\",\"foreground\":\"#000\",\"population\":0.23,\"title\":\"#000\"},\"muted\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#7e7e7e\",\"foreground\":\"#fff\",\"population\":1.04,\"title\":\"#fff\"},\"vibrant\":{\"_type\":\"sanity.imagePaletteSwatch\",\"background\":\"#6490e7\",\"foreground\":\"#fff\",\"population\":1.21,\"title\":\"#fff\"}}},\"mimeType\":\"image/svg+xml\",\"originalFilename\":\"nav-platform-cta-aperture-2.svg\",\"path\":\"images/w77i7m8x/production-v2/7fbf14ac75bdf258eeff9efb2a2d5bbbf2e87098-266x342.svg\",\"sha1hash\":\"7fbf14ac75bdf258eeff9efb2a2d5bbbf2e87098\",\"size\":982603,\"uploadId\":\"zOFizzW077I05H6oARSzfK7gcjwqQZCn\",\"url\":\"https://cdn.sanity.io/images/w77i7m8x/production-v2/7fbf14ac75bdf258eeff9efb2a2d5bbbf2e87098-266x342.svg\"}},\"title\":\"Aperture
+        by Tailscale\"},\"label\":\"Platform\",\"tray\":{\"buttons\":[{\"_key\":\"3388b94d369d\",\"_type\":\"buttonsMember\",\"openInNewTab\":false,\"text\":\"Read
+        more\",\"url\":\"https://tailscale.com/winter-update-week-26\"}],\"contentText\":\"The
+        latest improvements on Aperture, Peer Relays, Services, and more.\",\"title\":\"Tailscale
+        Winter Update\"}},{\"feature\":null,\"label\":\"Customer Stories\",\"tray\":null},{\"feature\":null,\"label\":\"Community\",\"tray\":{\"buttons\":[{\"_key\":\"06c200585c0f\",\"_type\":\"buttonsMember\",\"openInNewTab\":false,\"text\":\"Learn
+        more\",\"url\":\"https://tailscale.com/tailscaleup\"}],\"contentText\":\"Tailscale\u2019s
+        conference for engineering, security, and IT leaders.\",\"title\":\"Join us
+        at TailscaleUp\"}},{\"feature\":null,\"label\":\"Partnerships\",\"tray\":null}],\"title\":\"Production
+        Header\"},\"newAnnouncement\":{\"icon\":null,\"link\":{\"label\":\"Read more
+        \u2192\",\"url\":\"https://tailscale.com/blog/aperture-self-serve/?utm_source=announcement-bar\\u0026utm_medium=content\\u0026utm_campaign=aperture-self-serve\"},\"text\":\"APERTURE
+        IS NOW AVAILABLE - START BUILDING WITH AI SAFELY IN MINUTES, NO WAITLIST.\",\"themeColor\":\"purple\",\"title\":\"Production
+        Announcement\"}}},\"__N_SSG\":true},\"page\":\"/404\",\"query\":{},\"buildId\":\"yXNXD6wKMziT90Wz_CAoa\",\"isFallback\":false,\"gsp\":true,\"scriptLoader\":[]}</script></body></html>"
+    headers:
+      Age:
+      - '62'
+      Cache-Control:
+      - public, max-age=0, must-revalidate
+      Connection:
+      - close
+      Content-Length:
+      - '78615'
+      Content-Security-Policy-Report-Only:
+      - "default-src 'self' wwwv2.tailscale.com;\tscript-src 'self' wwwv2.tailscale.com
+        bat.bing.com cdn.rudderlabs.com www.google-analytics.com www.googletagmanager.com
+        www.google.com *.mutinycdn.com js.hs-scripts.com js.hs-banner.com js.hubspot.com
+        js.hs-analytics.com *.hsforms.net unpkg.com snap.licdn.com www.redditstatic.com
+        https://bwa.marketplace.awsstatic.com widget.kapa.ai;\tconnect-src 'self'
+        wwwv2.tailscale.com login.tailscale.com bat.bing.com *.mutinyhq.io *.mutinycdn.com
+        analytics.google.com www.google-analytics.com cdn.sanity.io unpkg.com *.rudderstack.com
+        *.hubspot.com www.redditstatic.com pixel-config.reddit.com px.ads.linkedin.com
+        https://medley.prod.irtysh.dubai.aws.dev proxy.kapa.ai kapa-widget-proxy-la7dkmplpq-uc.a.run.app
+        metrics.kapa.ai;\timg-src 'self' wwwv2.tailscale.com cdn.sanity.io lh3.googleusercontent.com
+        www.google-analytics.com *.hsforms.com alb.reddit.com px.ads.linkedin.com
+        bat.bing.com track.hubspot.com;\tframe-ancestors 'none';\tform-action 'self'
+        wwwv2.tailscale.com;\tbase-uri 'self' wwwv2.tailscale.com;\tblock-all-mixed-content;\tobject-src
+        'self' wwwv2.tailscale.com;\treport-to csp-endpoint;\treport-uri https://login.tailscale.com/csp-report;"
+      Content-Type:
+      - text/html; charset=utf-8
+      Date:
+      - Sat, 28 Mar 2026 11:27:17 GMT
+      Etag:
+      - '"yw4bnmoqu71omt"'
+      Reporting-Endpoints:
+      - csp-endpoint="https://login.tailscale.com/csp-report"
+      Server:
+      - Vercel
+      Strict-Transport-Security:
+      - max-age=63072000
+      X-Matched-Path:
+      - /[...slug]
+      X-Vercel-Cache:
+      - HIT
+      X-Vercel-Id:
+      - lhr1::iad1::vc7vg-1774697299824-ba5a8b5f5776
+    status:
+      code: 404
+      message: Not Found
+version: 1

tests/stubs/vcr.cassette.pyi (20) → tests/stubs/vcr.cassette.pyi (31)

diff --git a/tests/stubs/vcr.cassette.pyi b/tests/stubs/vcr.cassette.pyi
index 5c8ea15..4da50ac 100644
--- a/tests/stubs/vcr.cassette.pyi
+++ b/tests/stubs/vcr.cassette.pyi
@@ -1 +1,2 @@
-class Cassette: ...
+class Cassette:
+    _path: str

tests/stubs/vcr.pyi (0) → tests/stubs/vcr.pyi (342)

diff --git a/tests/stubs/vcr.pyi b/tests/stubs/vcr.pyi
new file mode 100644
index 0000000..7df326e
--- /dev/null
+++ b/tests/stubs/vcr.pyi
@@ -0,0 +1,11 @@
+import contextlib
+
+from vcr.cassette import Cassette
+
+def use_cassette(
+    cassette_name: str,
+    cassette_library_dir: str,
+    decode_compressed_response: bool,
+    filter_query_parameters: list[tuple[str, str]] | None = None,
+    filter_headers: list[tuple[str, str]] | None = None,
+) -> contextlib.AbstractContextManager[Cassette]: ...

tests/test_cassettes.py (0) → tests/test_cassettes.py (3304)

diff --git a/tests/test_cassettes.py b/tests/test_cassettes.py
new file mode 100644
index 0000000..6a790a6
--- /dev/null
+++ b/tests/test_cassettes.py
@@ -0,0 +1,100 @@
+"""
+Tests for `cassettes`.
+"""
+
+import pytest
+from vcr.cassette import Cassette
+
+from cassettes import get_cassette_name
+
+
+def test_creates_cassette(cassette_name: str) -> None:
+    """
+    The filename of a VCR cassette is the test name, plus a YAML extension.
+    """
+    assert cassette_name == "test_creates_cassette.yml"
+
+
+@pytest.mark.parametrize(
+    ["expected_cassette_name"],
+    [
+        pytest.param("test_creates_parametrized_cassette[test1].yml", id="test1"),
+        pytest.param("test_creates_parametrized_cassette[test2].yml", id="test2"),
+        pytest.param("test_creates_parametrized_cassette[test3].yml", id="test3"),
+    ],
+)
+def test_creates_parametrized_cassette(
+    cassette_name: str, expected_cassette_name: str
+) -> None:
+    """
+    In a parametrized test, the filename of the VCR cassette includes
+    the test case name in square brackets.
+    """
+    assert cassette_name == expected_cassette_name
+
+
+class TestCassetteNameInClass:
+    """
+    TestCassetteNameInClass exists so the next test can run inside
+    a class, simulating how tests are often organised in "real" test suites.
+    """
+
+    def test_prefixes_class_name_to_cassette(self, cassette_name: str) -> None:
+        """
+        In a test in a class, the filename of the VCR cassette includes
+        the class name as a prefix.
+        """
+        assert (
+            cassette_name
+            == "TestCassetteNameInClass.test_prefixes_class_name_to_cassette.yml"
+        )
+
+    @pytest.mark.parametrize(
+        ["expected_cassette_name"],
+        [
+            pytest.param(
+                "TestCassetteNameInClass.test_prefixes_name_with_parametrized_cassette[test1].yml",
+                id="test1",
+            ),
+            pytest.param(
+                "TestCassetteNameInClass.test_prefixes_name_with_parametrized_cassette[test2].yml",
+                id="test2",
+            ),
+            pytest.param(
+                "TestCassetteNameInClass.test_prefixes_name_with_parametrized_cassette[test3].yml",
+                id="test3",
+            ),
+            pytest.param(
+                "TestCassetteNameInClass.test_prefixes_name_with_parametrized_cassette[test.name.with.periods].yml",
+                id="test.name.with.periods",
+            ),
+        ],
+    )
+    def test_prefixes_name_with_parametrized_cassette(
+        self, cassette_name: str, expected_cassette_name: str
+    ) -> None:
+        """
+        In a parametrized test in a class, the filename of the
+        VCR cassette includes the class name as a prefix and the
+        test case name as a suffix.
+        """
+        assert cassette_name == expected_cassette_name
+
+
+@pytest.mark.parametrize("url", ["https://example.com"])
+def test_throws_if_bad_cassette_name(url: str, request: pytest.FixtureRequest) -> None:
+    """
+    Trying to use a URL as a VCR cassette name throws a ``ValueError``.
+    """
+    with pytest.raises(ValueError, match="Illegal characters in VCR cassette name"):
+        get_cassette_name(request)
+
+
+def test_creates_cassette_in_fixture_dir(vcr_cassette: Cassette) -> None:
+    """
+    The VCR cassette is created in the ``tests/fixtures/cassettes`` directory.
+    """
+    assert (
+        vcr_cassette._path
+        == "tests/fixtures/cassettes/test_creates_cassette_in_fixture_dir.yml"
+    )

tests/test_urls.py (4359) → tests/test_urls.py (4358)

diff --git a/tests/test_urls.py b/tests/test_urls.py
index b33f807..4fdb2bd 100644
--- a/tests/test_urls.py
+++ b/tests/test_urls.py
@@ -123,7 +123,7 @@ class TestIsMastodonHost:
             # These are regular Internet websites which don't expose
             # the /.well-known/nodeinfo endpoint
             "example.com",
-            "alexwlchan.net",
+            "tailscale.com",
             #
             # PeerTube exposes /.well-known/nodeinfo, but it's running
             # different software.