mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-26 08:53:05 +00:00
feat(windows): add /windows endpoint for Windows configuration
- registry file /windows/tailscale.reg is generated, filling in the associated control server URL - also includes CLI instructions - fix /apple incorrect template: 'Url' is supposed to be '.URL'
This commit is contained in:
parent
b342cf0240
commit
12a50ac8ac
2 changed files with 108 additions and 0 deletions
2
app.go
2
app.go
|
@ -458,6 +458,8 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *gin.Engine {
|
||||||
router.GET("/oidc/callback", h.OIDCCallback)
|
router.GET("/oidc/callback", h.OIDCCallback)
|
||||||
router.GET("/apple", h.AppleConfigMessage)
|
router.GET("/apple", h.AppleConfigMessage)
|
||||||
router.GET("/apple/:platform", h.ApplePlatformConfig)
|
router.GET("/apple/:platform", h.ApplePlatformConfig)
|
||||||
|
router.GET("/windows", h.WindowsConfigMessage)
|
||||||
|
router.GET("/windows/tailscale.reg", h.WindowsRegConfig)
|
||||||
router.GET("/swagger", SwaggerUI)
|
router.GET("/swagger", SwaggerUI)
|
||||||
router.GET("/swagger/v1/openapiv2.json", SwaggerAPIv1)
|
router.GET("/swagger/v1/openapiv2.json", SwaggerAPIv1)
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,100 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WindowsConfigMessage shows a simple message in the browser for how to
|
||||||
|
// configure the Windows tailscale client.
|
||||||
|
func (h *Headscale) WindowsConfigMessage(ctx *gin.Context) {
|
||||||
|
winTemplate := template.Must(template.New("windows").Parse(`
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>headscale</h1>
|
||||||
|
<h2>Windows registry configuration</h2>
|
||||||
|
<p>
|
||||||
|
This page provides Windows registry information for the official Windows Tailscale client.
|
||||||
|
<p>
|
||||||
|
<p>
|
||||||
|
The registry file will configure Tailscale to use <code>{{.URL}}</code> as its control server.
|
||||||
|
<p>
|
||||||
|
<h3>Caution</h3>
|
||||||
|
<p>You should always download and inspect the registry file before installing it:</p>
|
||||||
|
<pre><code>curl {{.URL}}/windows/tailscale.reg</code></pre>
|
||||||
|
|
||||||
|
<h2>Installation</h2>
|
||||||
|
<p>Headscale can be set to the default server by running the registry file:</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="/windows/tailscale.reg" download="tailscale.reg">Windows registry file</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Download the registry file, then run it</li>
|
||||||
|
<li>Follow the prompts</li>
|
||||||
|
<li>Install and run the official windows Tailscale client</li>
|
||||||
|
<li>When the installation has finished, start Tailscale, and log in by clicking the icon in the system tray</li>
|
||||||
|
</ol>
|
||||||
|
<p>Or</p>
|
||||||
|
<p>Open command prompt with Administrator rights. Issue the following commands to add the required registry entries:</p>
|
||||||
|
<pre>
|
||||||
|
<code>REG ADD "HKLM\Software\Tailscale IPN" /v UnattendedMode /t REG_SZ /d always
|
||||||
|
REG ADD "HKLM\Software\Tailscale IPN" /v LoginURL /t REG_SZ /d "{{.URL}}"</code></pre>
|
||||||
|
<p>
|
||||||
|
Restart Tailscale and log in.
|
||||||
|
<p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`))
|
||||||
|
|
||||||
|
config := map[string]interface{}{
|
||||||
|
"URL": h.cfg.ServerURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload bytes.Buffer
|
||||||
|
if err := winTemplate.Execute(&payload, config); err != nil {
|
||||||
|
log.Error().
|
||||||
|
Str("handler", "WindowsRegConfig").
|
||||||
|
Err(err).
|
||||||
|
Msg("Could not render Windows index template")
|
||||||
|
ctx.Data(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
"text/html; charset=utf-8",
|
||||||
|
[]byte("Could not render Windows index template"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data(http.StatusOK, "text/html; charset=utf-8", payload.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowsRegConfig generates and serves the .reg file
|
||||||
|
// pre-configured to the headscale server address
|
||||||
|
func (h *Headscale) WindowsRegConfig(ctx *gin.Context) {
|
||||||
|
config := WindowsRegistryConfig{
|
||||||
|
URL: h.cfg.ServerURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
var content bytes.Buffer
|
||||||
|
if err := windowsRegTemplate.Execute(&content, config); err != nil {
|
||||||
|
log.Error().
|
||||||
|
Str("handler", "WindowsRegConfig").
|
||||||
|
Err(err).
|
||||||
|
Msg("Could not render Apple macOS template")
|
||||||
|
ctx.Data(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
"text/html; charset=utf-8",
|
||||||
|
[]byte("Could not render Windows registry template"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data(
|
||||||
|
http.StatusOK,
|
||||||
|
"text/x-ms-regedit; charset=utf-8",
|
||||||
|
content.Bytes(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// AppleConfigMessage shows a simple message in the browser to point the user
|
// AppleConfigMessage shows a simple message in the browser to point the user
|
||||||
// to the iOS/MacOS profile and instructions for how to install it
|
// to the iOS/MacOS profile and instructions for how to install it
|
||||||
func (h *Headscale) AppleConfigMessage(ctx *gin.Context) {
|
func (h *Headscale) AppleConfigMessage(ctx *gin.Context) {
|
||||||
|
@ -193,6 +287,10 @@ func (h *Headscale) ApplePlatformConfig(ctx *gin.Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WindowsRegistryConfig struct {
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
type AppleMobileConfig struct {
|
type AppleMobileConfig struct {
|
||||||
UUID uuid.UUID
|
UUID uuid.UUID
|
||||||
URL string
|
URL string
|
||||||
|
@ -204,6 +302,14 @@ type AppleMobilePlatformConfig struct {
|
||||||
URL string
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var windowsRegTemplate = textTemplate.Must(
|
||||||
|
textTemplate.New("windowsconfig").Parse(`Windows Registry Editor Version 5.00
|
||||||
|
|
||||||
|
[HKEY_LOCAL_MACHINE\SOFTWARE\Tailscale IPN]
|
||||||
|
"UnattendedMode"="always"
|
||||||
|
"LoginURL"="{{.URL}}"
|
||||||
|
`))
|
||||||
|
|
||||||
var commonTemplate = textTemplate.Must(
|
var commonTemplate = textTemplate.Must(
|
||||||
textTemplate.New("mobileconfig").Parse(`<?xml version="1.0" encoding="UTF-8"?>
|
textTemplate.New("mobileconfig").Parse(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
|
Loading…
Reference in a new issue