tailscale/cmd/tailtlsproxy/main.go
Xe 4d5386001a cmd/tailtlsproxy: introduce HTTPS proxy bridge
This allows you to bridge existing HTTP/S services into your tailnet
using the Let's Encrypt[1] functionality. This will allow you to run
multiple services on the same computer and still have them point at
different target HTTP services.

This also includes an example systemd template unit that lets you easily
set up multiple instances of tailtlsproxy on the same machine.

[1]: https://tailscale.com/blog/tls-certs/

Signed-off-by: Xe <xe@tailscale.com>
2021-11-19 10:50:28 -05:00

87 lines
1.9 KiB
Go

// 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))
}