@ -7,6 +7,7 @@ package cli
import (
"bytes"
"context"
"crypto/tls"
_ "embed"
"encoding/json"
"encoding/xml"
@ -19,6 +20,7 @@ import (
"net/http"
"net/http/cgi"
"net/url"
"os"
"os/exec"
"runtime"
"strings"
@ -83,6 +85,29 @@ var webArgs struct {
cgi bool
}
func tlsConfigFromEnvironment ( ) * tls . Config {
crt := os . Getenv ( "TLS_CRT_PEM" )
key := os . Getenv ( "TLS_KEY_PEM" )
if crt == "" || key == "" {
return nil
}
// We support passing in the complete certificate and key from environment
// variables because pfSense stores its cert+key in the PHP config. We populate
// TLS_CRT_PEM and TLS_KEY_PEM from PHP code before starting tailscale web.
// These are the PEM-encoded Certificate and Private Key.
cert , err := tls . X509KeyPair ( [ ] byte ( crt ) , [ ] byte ( key ) )
if err != nil {
log . Printf ( "tlsConfigFromEnvironment: %v" , err )
// Fallback to unencrypted HTTP.
return nil
}
return & tls . Config { Certificates : [ ] tls . Certificate { cert } }
}
func runWeb ( ctx context . Context , args [ ] string ) error {
if len ( args ) > 0 {
log . Fatalf ( "too many non-flag arguments: %q" , args )
@ -96,8 +121,20 @@ func runWeb(ctx context.Context, args []string) error {
return nil
}
log . Printf ( "web server running on: %s" , urlOfListenAddr ( webArgs . listen ) )
return http . ListenAndServe ( webArgs . listen , http . HandlerFunc ( webHandler ) )
tlsConfig := tlsConfigFromEnvironment ( )
if tlsConfig != nil {
server := & http . Server {
Addr : webArgs . listen ,
TLSConfig : tlsConfig ,
Handler : http . HandlerFunc ( webHandler ) ,
}
log . Printf ( "web server runNIng on: https://%s" , server . Addr )
return server . ListenAndServeTLS ( "" , "" )
} else {
log . Printf ( "web server running on: %s" , urlOfListenAddr ( webArgs . listen ) )
return http . ListenAndServe ( webArgs . listen , http . HandlerFunc ( webHandler ) )
}
}
// urlOfListenAddr parses a given listen address into a formatted URL