<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> <title>Hello from Tailscale</title> <style> html, body { margin: 0; padding: 0; } body { font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 100%; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } html, body, main { height: 100%; } *, ::before, ::after { box-sizing: border-box; border-width: 0; border-style: solid; border-color: #dad6d5; } h1, h2, h3, h4, h5, h6 { margin: 0; font-size: 1rem; font-weight: inherit; } a { color: inherit; } p { margin: 0; } main { display: flex; flex-direction: column; justify-content: center; align-items: center; max-width: 24rem; width: 95%; margin-left: auto; margin-right: auto; } .p-2 { padding: 0.5rem; } .p-4 { padding: 1rem; } .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; } .pl-3 { padding-left: 0.75rem; } .pr-3 { padding-right: 0.75rem; } .pt-4 { padding-top: 1rem; } .mr-2 { margin-right: 0.5rem; ; } .mb-1 { margin-bottom: 0.25rem; } .mb-2 { margin-bottom: 0.5rem; } .mb-4 { margin-bottom: 1rem; } .mb-6 { margin-bottom: 1.5rem; } .mb-8 { margin-bottom: 2rem; } .mb-12 { margin-bottom: 3rem; } .width-full { width: 100%; } .min-width-0 { min-width: 0; } .rounded-lg { border-radius: 0.5rem; } .relative { position: relative; } .flex { display: flex; } .justify-between { justify-content: space-between; } .items-center { align-items: center; } .border { border-width: 1px; } .border-t-1 { border-top-width: 1px; } .border-gray-100 { border-color: #f7f5f4; } .border-gray-200 { border-color: #eeebea; } .border-gray-300 { border-color: #dad6d5; } .bg-white { background-color: white; } .bg-gray-0 { background-color: #faf9f8; } .bg-gray-100 { background-color: #f7f5f4; } .text-green-600 { color: #0d4b3b; } .text-blue-600 { color: #3f5db3; } .hover\:text-blue-800:hover { color: #253570; } .text-gray-600 { color: #444342; } .text-gray-700 { color: #2e2d2d; } .text-gray-800 { color: #232222; } .text-center { text-align: center; } .text-sm { font-size: 0.875rem; } .font-title { font-size: 1.25rem; letter-spacing: -0.025em; } .font-semibold { font-weight: 600; } .font-medium { font-weight: 500; } .font-regular { font-weight: 400; } .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .overflow-hidden { overflow: hidden; } .profile-pic { width: 2.5rem; height: 2.5rem; border-radius: 9999px; background-size: cover; margin-right: 0.5rem; flex-shrink: 0; } .panel { box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); } .animate .panel { transform: translateY(10%); box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.0), 0 10px 10px -5px rgba(0, 0, 0, 0.0); transition: transform 1200ms ease, opacity 1200ms ease, box-shadow 1200ms ease; } .animate .panel-interior { opacity: 0.0; transition: opacity 1200ms ease; } .animate .logo { transform: translateY(2rem); opacity: 0.0; transition: transform 1200ms ease, opacity 1200ms ease; } .animate .header-title { transform: translateY(1.6rem); opacity: 0.0; transition: transform 1200ms ease, opacity 1200ms ease; } .animate .header-text { transform: translateY(1.2rem); opacity: 0.0; transition: transform 1200ms ease, opacity 1200ms ease; } .animate .footer { transform: translateY(-0.5rem); opacity: 0.0; transition: transform 1200ms ease, opacity 1200ms ease; } .animating .panel { transform: translateY(0); opacity: 1.0; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); } .animating .panel-interior { opacity: 1.0; } .animating .spinner { opacity: 0.0; } .animating .logo, .animating .header-title, .animating .header-text, .animating .footer { transform: translateY(0); opacity: 1.0; } .spinner { display: inline-flex; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); align-items: center; transition: opacity 200ms ease; } .spinner span { display: inline-block; background-color: currentColor; border-radius: 9999px; animation-name: loading-dots-blink; animation-duration: 1.4s; animation-iteration-count: infinite; animation-fill-mode: both; width: 0.35em; height: 0.35em; margin: 0 0.15em; } .spinner span:nth-child(2) { animation-delay: 200ms; } .spinner span:nth-child(3) { animation-delay: 400ms; } .spinner { display: none; } .animate .spinner { display: inline-flex; } @keyframes loading-dots-blink { 0% { opacity: 0.2; } 20% { opacity: 1; } 100% { opacity: 0.2; } } @media (prefers-reduced-motion) { * { animation-duration: 0ms !important; transition-duration: 0ms !important; transition-delay: 0ms !important; } } </style> </head> <body class="bg-gray-100"> <script> (function() { var lastSeen = localStorage.getItem("lastSeen"); if (!lastSeen) { document.body.classList.add("animate"); window.addEventListener("load", function () { setTimeout(function () { document.body.classList.add("animating"); localStorage.setItem("lastSeen", Date.now()); }, 100); }); } })(); </script> <main class="text-gray-800"> <svg class="logo mb-6" width="28" height="28" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle opacity="0.2" cx="3.4" cy="3.25" r="2.7" fill="currentColor" /> <circle cx="3.4" cy="11.3" r="2.7" fill="currentColor" /> <circle opacity="0.2" cx="3.4" cy="19.5" r="2.7" fill="currentColor" /> <circle cx="11.5" cy="11.3" r="2.7" fill="currentColor" /> <circle cx="11.5" cy="19.5" r="2.7" fill="currentColor" /> <circle opacity="0.2" cx="11.5" cy="3.25" r="2.7" fill="currentColor" /> <circle opacity="0.2" cx="19.5" cy="3.25" r="2.7" fill="currentColor" /> <circle cx="19.5" cy="11.3" r="2.7" fill="currentColor" /> <circle opacity="0.2" cx="19.5" cy="19.5" r="2.7" fill="currentColor" /> </svg> <header class="mb-8 text-center"> <h1 class="header-title font-title font-semibold mb-2">You're connected over Tailscale!</h1> <p class="header-text">This device is signed in as…</p> </header> <div class="panel relative bg-white rounded-lg width-full shadow-xl mb-8 p-4"> <div class="spinner text-gray-600"> <span></span> <span></span> <span></span> </div> <div class="panel-interior flex items-center width-full min-width-0 p-2 mb-4"> <div class="profile-pic bg-gray-100" style="background-image: url({{.ProfilePicURL}});"></div> <div class="overflow-hidden"> {{ with .DisplayName }} <h4 class="font-semibold truncate">{{.}}</h4> {{ end }} <h5 class="text-gray-600 truncate">{{.LoginName}}</h5> </div> </div> <div class="panel-interior border border-gray-200 bg-gray-0 rounded-lg p-2 pl-3 pr-3 mb-2 width-full flex justify-between items-center"> <div class="flex items-center min-width-0"> <svg class="text-gray-600 mr-2" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect> <rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect> <line x1="6" y1="6" x2="6.01" y2="6"></line> <line x1="6" y1="18" x2="6.01" y2="18"></line> </svg> <h4 class="font-semibold truncate mr-2">{{.MachineName}}</h4> </div> <h5>{{.IP}}</h5> </div> </div> <footer class="footer text-gray-600 text-center mb-12"> <p>Read about <a href="https://tailscale.com/kb/1017/install#advanced-features" class="text-blue-600 hover:text-blue-800" target="_blank">what you can do next →</a></p> <p>Read about <a href="https://tailscale.com/kb/1073/hello" class="text-blue-600 hover:text-blue-800" target="_blank">the Hello service →</a></p> </footer> </main> </body> </html>