diff --git a/cmd/tailtlsproxy/main.go b/cmd/tailtlsproxy/main.go new file mode 100644 index 000000000..b5fe35a48 --- /dev/null +++ b/cmd/tailtlsproxy/main.go @@ -0,0 +1,86 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "crypto/tls" + "flag" + "log" + "net/http" + "net/http/httputil" + "net/url" + "os" + "time" + + "tailscale.com/client/tailscale" + "tailscale.com/tsnet" +) + +func envOr(name, def string) string { + if val, ok := os.LookupEnv(name); ok { + return val + } + + return def +} + +var ( + bind = flag.String("bind", ":443", "TCP hostport to bind to for TLS http traffic") + hostname = flag.String("hostname", envOr("HOSTNAME", "toolname"), "hostname to register on tailnet (can be set with $HOSTNAME)") + auth = flag.Bool("auth", false, "if set, authenticate with tailscale (enables verbose logging)") + v = flag.Bool("v", false, "if set, enable verbose tailscale logs") + to = flag.String("to", envOr("TO", "http://127.0.0.1:3030"), "HTTP/S url to reverse proxy to (can be set with $TO)") +) + +func main() { + os.Setenv("TAILSCALE_USE_WIP_CODE", "true") + flag.Parse() + + srv := tsnet.Server{ + Hostname: *hostname, + } + + if *auth || *v { + srv.Logf = log.Printf + } else { + srv.Logf = func(string, ...interface{}) {} + } + + if *auth { + os.Setenv("TS_LOGIN", "1") + } + + ln, err := srv.Listen("tcp", *bind) + if err != nil { + log.Fatal(err) + } + + u, err := url.Parse(*to) + if err != nil { + log.Fatalf("%s wasn't a valid URL: %v", *to, err) + } + + h := httputil.NewSingleHostReverseProxy(u) + + ln = tls.NewListener(ln, &tls.Config{ + GetCertificate: func(chi *tls.ClientHelloInfo) (*tls.Certificate, error) { + c, err := tailscale.GetCertificate(chi) + if err != nil { + log.Println(err) + } + return c, err + }, + }) + + s := &http.Server{ + IdleTimeout: 5 * time.Minute, + Addr: *bind, + Handler: h, + } + + log.Printf("listening for https on https://%s.your.tailcert.domain and forwarding to %s", *hostname, *to) + + log.Fatal(s.Serve(ln)) +} diff --git a/cmd/tailtlsproxy/tailtlsproxy-test.defaults b/cmd/tailtlsproxy/tailtlsproxy-test.defaults new file mode 100644 index 000000000..9a5e3991d --- /dev/null +++ b/cmd/tailtlsproxy/tailtlsproxy-test.defaults @@ -0,0 +1,2 @@ +HOSTNAME=test +TO=http://127.0.0.1:3030 diff --git a/cmd/tailtlsproxy/tailtlsproxy@.service b/cmd/tailtlsproxy/tailtlsproxy@.service new file mode 100644 index 000000000..78505da39 --- /dev/null +++ b/cmd/tailtlsproxy/tailtlsproxy@.service @@ -0,0 +1,19 @@ +[Unit] +Description=Tailscale TLS Proxy bridge for %i +After=network.target + +[Service] +Environment=HOME=/var/lib/private/tailtlsproxy-%i +EnvironmentFile=/etc/default/tailtlsproxy-%i +ExecStart=/usr/bin/tailtlsproxy +Restart=on-failure +RuntimeDirectory=tailtlsproxy-%i +RuntimeDirectoryMode=0755 +StateDirectory=tailtlsproxy-%i +StateDirectoryMode=0700 +CacheDirectory=tailtlsproxy-%i +CacheDirectoryMode=0750 +DynamicUser=yes + +[Install] +WantedBy=multi-user.target \ No newline at end of file