Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
jordi fita mas | 4e54041818 | |
jordi fita mas | 13c5968333 |
|
@ -1,6 +1,6 @@
|
||||||
# [tlstunnel]
|
# [tlstunnel]
|
||||||
|
|
||||||
[![builds.sr.ht status](https://builds.sr.ht/~emersion/tlstunnel/commits/master.svg)](https://builds.sr.ht/~emersion/tlstunnel/commits/master?)
|
[![builds.sr.ht status](https://builds.sr.ht/~emersion/tlstunnel/commits.svg)](https://builds.sr.ht/~emersion/tlstunnel/commits?)
|
||||||
|
|
||||||
A TLS reverse proxy.
|
A TLS reverse proxy.
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ import (
|
||||||
var (
|
var (
|
||||||
configPath = "config"
|
configPath = "config"
|
||||||
certDataPath = ""
|
certDataPath = ""
|
||||||
|
|
||||||
debug = false
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newServer() (*tlstunnel.Server, error) {
|
func newServer() (*tlstunnel.Server, error) {
|
||||||
|
@ -28,7 +26,6 @@ func newServer() (*tlstunnel.Server, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := tlstunnel.NewServer()
|
srv := tlstunnel.NewServer()
|
||||||
srv.Debug = debug
|
|
||||||
|
|
||||||
loggerCfg := zap.Config{
|
loggerCfg := zap.Config{
|
||||||
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
|
Level: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||||
|
@ -71,7 +68,6 @@ func bumpOpenedFileLimit() error {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.StringVar(&configPath, "config", configPath, "path to configuration file")
|
flag.StringVar(&configPath, "config", configPath, "path to configuration file")
|
||||||
flag.BoolVar(&debug, "debug", false, "enable debug logging")
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if err := bumpOpenedFileLimit(); err != nil {
|
if err := bumpOpenedFileLimit(); err != nil {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
tlstunnel (0.2.0-2) bookworm; urgency=medium
|
||||||
|
|
||||||
|
* Set default config and certificates path with linker flags
|
||||||
|
|
||||||
|
-- jordi fita mas <jordi@tandem.blog> Thu, 15 Jun 2023 13:19:45 +0000
|
||||||
|
|
||||||
|
tlstunnel (0.2.0-1) bullseye; urgency=medium
|
||||||
|
|
||||||
|
* Add Debian packaging
|
||||||
|
|
||||||
|
-- jordi fita mas <jordi@tandem.blog> Wed, 14 Jun 2023 20:40:39 +0000
|
|
@ -0,0 +1,37 @@
|
||||||
|
Source: tlstunnel
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: jordi fita mas <jordi@tandem.blog>
|
||||||
|
Build-Depends:
|
||||||
|
debhelper-compat (= 13),
|
||||||
|
dh-golang,
|
||||||
|
golang-any,
|
||||||
|
golang-sourcehut-emersion-go-scfg-dev,
|
||||||
|
golang-github-caddyserver-certmagic-dev,
|
||||||
|
golang-github-klauspost-cpuid-dev,
|
||||||
|
golang-github-libdns-libdns-dev,
|
||||||
|
golang-github-pires-go-proxyproto-dev,
|
||||||
|
golang-github-pkg-errors-dev,
|
||||||
|
golang-go.uber-atomic-dev,
|
||||||
|
golang-go.uber-multierr-dev,
|
||||||
|
golang-go.uber-zap-dev,
|
||||||
|
golang-golang-x-crypto-dev,
|
||||||
|
golang-golang-x-tools-dev,
|
||||||
|
scdoc
|
||||||
|
Standards-Version: 4.6.0
|
||||||
|
Vcs-Browser: https://git.sr.ht/~emersion/tlstunnel/tree
|
||||||
|
Vcs-Git: https://git.sr.ht/~emersion/tlstunnel
|
||||||
|
Homepage: https://git.sr.ht/~emersion/tlstunnel
|
||||||
|
Rules-Requires-Root: no
|
||||||
|
XS-Go-Import-Path: git.sr.ht/~emersion/tlstunnel
|
||||||
|
|
||||||
|
Package: tlstunnel
|
||||||
|
Architecture: any
|
||||||
|
Depends:
|
||||||
|
${shlibs:Depends},
|
||||||
|
${misc:Depends}
|
||||||
|
Built-Using: ${misc:Built-Using}
|
||||||
|
description: TLS reverse proxy
|
||||||
|
.
|
||||||
|
It features: Automatic TLS with Let's Encrypt, routing incoming connections to
|
||||||
|
backends using Server Name Indication, and support for the PROXY protocol.
|
|
@ -0,0 +1,31 @@
|
||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Source: https://git.sr.ht/~emersion/tlstunnel
|
||||||
|
Upstream-Name: tlstunnel
|
||||||
|
Upstream-Contact: ~emersion/public-inbox@lists.sr.ht
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2020–2023 Simon Ser
|
||||||
|
License: MIT
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
.
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Files: debian/*
|
||||||
|
Copyright: 2023 jordi fita mas
|
||||||
|
License: MIT
|
||||||
|
This debian package is distributed under the same license as the source
|
||||||
|
package.
|
|
@ -0,0 +1 @@
|
||||||
|
tlstunnel.1
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
. /usr/share/debconf/confmodule
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
configure)
|
||||||
|
# Create tlstunnel user and group
|
||||||
|
if ! getent group tlstunnel >/dev/null; then
|
||||||
|
addgroup --system --quiet tlstunnel
|
||||||
|
fi
|
||||||
|
if ! getent passwd tlstunnel >/dev/null; then
|
||||||
|
adduser --quiet \
|
||||||
|
--system \
|
||||||
|
--disabled-login \
|
||||||
|
--no-create-home \
|
||||||
|
--shell /bin/bash \
|
||||||
|
--ingroup tlstunnel \
|
||||||
|
--home /var/lib/tlstunnel \
|
||||||
|
--gecos "tlstunnel daemon" \
|
||||||
|
tlstunnel
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure lib directory has correct permissions set
|
||||||
|
dpkg-statoverride --list "/var/lib/tlstunnel" >/dev/null || \
|
||||||
|
dpkg-statoverride --add --force --quiet --update tlstunnel adm 0750 /var/lib/tlstunnel
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "postinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
exit 0
|
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
GO_LDFLAGS += -X 'main.configPath=/etc/tlstunnel'
|
||||||
|
GO_LDFLAGS += -X 'main.certDataPath=/var/lib/tlstunnel'
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --builddirectory=_build --buildsystem=golang --with=golang
|
||||||
|
|
||||||
|
execute_before_dh_auto_build:
|
||||||
|
make tlstunnel.1
|
||||||
|
|
||||||
|
override_dh_auto_build:
|
||||||
|
dh_auto_build -- -ldflags "$(GO_LDFLAGS)"
|
|
@ -0,0 +1 @@
|
||||||
|
3.0 (quilt)
|
|
@ -0,0 +1 @@
|
||||||
|
../contrib/systemd/tlstunnel.service
|
|
@ -0,0 +1 @@
|
||||||
|
../contrib/systemd/tlstunnel.tmpfiles
|
|
@ -1,17 +1,12 @@
|
||||||
package tlstunnel
|
package tlstunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/subtle"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.sr.ht/~emersion/go-scfg"
|
"git.sr.ht/~emersion/go-scfg"
|
||||||
|
@ -135,64 +130,6 @@ func parseBackend(backend *Backend, d *scfg.Directive) error {
|
||||||
return fmt.Errorf("failed to setup backend %q: unsupported URI scheme", backendURI)
|
return fmt.Errorf("failed to setup backend %q: unsupported URI scheme", backendURI)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, child := range d.Children {
|
|
||||||
switch child.Name {
|
|
||||||
case "tls_certfp":
|
|
||||||
if backend.TLSConfig == nil {
|
|
||||||
return fmt.Errorf("tls_certfp requires a tls:// backend address")
|
|
||||||
}
|
|
||||||
|
|
||||||
var algo, wantCertFP string
|
|
||||||
if err := child.ParseParams(&algo, &wantCertFP); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if algo != "sha-256" {
|
|
||||||
return fmt.Errorf("directive tls_certfp: only sha-256 is supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
wantCertFP = strings.ReplaceAll(wantCertFP, ":", "")
|
|
||||||
wantSum, err := hex.DecodeString(wantCertFP)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("directive tls_certfp: invalid fingerprint: %v", err)
|
|
||||||
} else if len(wantSum) != sha256.Size {
|
|
||||||
return fmt.Errorf("directive tls_certfp: invalid fingerprint length")
|
|
||||||
}
|
|
||||||
|
|
||||||
backend.TLSConfig.InsecureSkipVerify = true
|
|
||||||
backend.TLSConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
|
||||||
if len(rawCerts) == 0 {
|
|
||||||
return fmt.Errorf("the server didn't present any TLS certificate")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rawCert := range rawCerts {
|
|
||||||
sum := sha256.Sum256(rawCert)
|
|
||||||
if subtle.ConstantTimeCompare(sum[:], wantSum) == 1 {
|
|
||||||
return nil // fingerprints match
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sum := sha256.Sum256(rawCerts[0])
|
|
||||||
remoteCertFP := hex.EncodeToString(sum[:])
|
|
||||||
return fmt.Errorf("configured TLS certificate fingerprint doesn't match the server's - %s", remoteCertFP)
|
|
||||||
}
|
|
||||||
case "proxy_version":
|
|
||||||
var version string
|
|
||||||
if err := child.ParseParams(&version); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
v, err := strconv.Atoi(version)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("directive proxy_version: invalid version: %v", err)
|
|
||||||
}
|
|
||||||
switch v {
|
|
||||||
case 1, 2:
|
|
||||||
backend.ProxyVersion = v
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("directive proxy_version: unknown version: %v", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,19 +175,6 @@ func parseTLS(srv *Server, d *scfg.Directive) error {
|
||||||
if err := parseTLSOnDemand(srv, child); err != nil {
|
if err := parseTLSOnDemand(srv, child); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "acme_dns_command":
|
|
||||||
var cmdName string
|
|
||||||
if err := child.ParseParams(&cmdName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cmdParams := child.Params[1:]
|
|
||||||
|
|
||||||
srv.ACMEIssuer.DNS01Solver = &certmagic.DNS01Solver{
|
|
||||||
DNSProvider: &commandDNSProvider{
|
|
||||||
Name: cmdName,
|
|
||||||
Params: cmdParams,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown %q directive", child.Name)
|
return fmt.Errorf("unknown %q directive", child.Name)
|
||||||
}
|
}
|
||||||
|
|
81
dns.go
81
dns.go
|
@ -1,81 +0,0 @@
|
||||||
package tlstunnel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/caddyserver/certmagic"
|
|
||||||
"github.com/libdns/libdns"
|
|
||||||
)
|
|
||||||
|
|
||||||
type commandDNSProvider struct {
|
|
||||||
Name string
|
|
||||||
Params []string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ certmagic.ACMEDNSProvider = (*commandDNSProvider)(nil)
|
|
||||||
|
|
||||||
func (provider *commandDNSProvider) exec(ctx context.Context, subcmd string, subargs ...string) error {
|
|
||||||
var params []string
|
|
||||||
params = append(params, provider.Params...)
|
|
||||||
params = append(params, subcmd)
|
|
||||||
params = append(params, subargs...)
|
|
||||||
cmd := exec.CommandContext(ctx, provider.Name, params...)
|
|
||||||
|
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
|
||||||
details := ""
|
|
||||||
if len(out) > 0 {
|
|
||||||
details = ": " + string(out)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to run DNS hook %v (%w)%v", subcmd, err, details)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *commandDNSProvider) processRecords(ctx context.Context, zone string, recs []libdns.Record, subcmd string) ([]libdns.Record, error) {
|
|
||||||
var (
|
|
||||||
done []libdns.Record
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
for _, rec := range recs {
|
|
||||||
var domain string
|
|
||||||
if domain, err = domainFromACMEChallengeRecord(zone, &rec); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err = provider.exec(ctx, subcmd, domain, "-", rec.Value); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
done = append(done, rec)
|
|
||||||
}
|
|
||||||
return done, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *commandDNSProvider) AppendRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) {
|
|
||||||
return provider.processRecords(ctx, zone, recs, "deploy_challenge")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *commandDNSProvider) DeleteRecords(ctx context.Context, zone string, recs []libdns.Record) ([]libdns.Record, error) {
|
|
||||||
return provider.processRecords(ctx, zone, recs, "clean_challenge")
|
|
||||||
}
|
|
||||||
|
|
||||||
func domainFromACMEChallengeRecord(zone string, rec *libdns.Record) (string, error) {
|
|
||||||
relZone := strings.TrimSuffix(zone, ".")
|
|
||||||
|
|
||||||
var domain string
|
|
||||||
if rec.Name == "_acme-challenge" {
|
|
||||||
// Root domain
|
|
||||||
domain = relZone
|
|
||||||
} else if strings.HasPrefix(rec.Name, "_acme-challenge.") {
|
|
||||||
// Subdomain
|
|
||||||
relName := strings.TrimPrefix(rec.Name, "_acme-challenge.")
|
|
||||||
domain = relName + "." + relZone
|
|
||||||
}
|
|
||||||
if rec.Type != "TXT" || domain == "" {
|
|
||||||
return "", fmt.Errorf("DNS record doesn't look like an ACME challenge: %v %v", rec.Type, rec.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return domain, nil
|
|
||||||
}
|
|
1
go.mod
1
go.mod
|
@ -6,7 +6,6 @@ require (
|
||||||
git.sr.ht/~emersion/go-scfg v0.0.0-20211215104734-c2c7a15d6c99
|
git.sr.ht/~emersion/go-scfg v0.0.0-20211215104734-c2c7a15d6c99
|
||||||
github.com/caddyserver/certmagic v0.17.2
|
github.com/caddyserver/certmagic v0.17.2
|
||||||
github.com/klauspost/cpuid/v2 v2.2.1 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.1 // indirect
|
||||||
github.com/libdns/libdns v0.2.1
|
|
||||||
github.com/pires/go-proxyproto v0.6.2
|
github.com/pires/go-proxyproto v0.6.2
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
|
|
30
server.go
30
server.go
|
@ -38,7 +38,6 @@ func newACMECache() *acmeCache {
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Listeners map[string]*Listener // indexed by listening address
|
Listeners map[string]*Listener // indexed by listening address
|
||||||
Frontends []*Frontend
|
Frontends []*Frontend
|
||||||
Debug bool
|
|
||||||
|
|
||||||
ManagedNames []string
|
ManagedNames []string
|
||||||
UnmanagedCerts []tls.Certificate
|
UnmanagedCerts []tls.Certificate
|
||||||
|
@ -187,10 +186,6 @@ func (srv *Server) Replace(old *Server) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type clientError struct {
|
|
||||||
error
|
|
||||||
}
|
|
||||||
|
|
||||||
type listenerHandles struct {
|
type listenerHandles struct {
|
||||||
Server *Server
|
Server *Server
|
||||||
Frontends map[string]*Frontend // indexed by server name
|
Frontends map[string]*Frontend // indexed by server name
|
||||||
|
@ -261,14 +256,8 @@ func (ln *Listener) serve() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := ln.handle(conn)
|
if err := ln.handle(conn); err != nil {
|
||||||
if err == nil {
|
log.Printf("listener %q: %v", ln.Address, err)
|
||||||
return
|
|
||||||
}
|
|
||||||
srv := ln.atomic.Load().(*listenerHandles).Server
|
|
||||||
var clientErr clientError
|
|
||||||
if !errors.As(err, &clientErr) || srv.Debug {
|
|
||||||
log.Printf("listener %q: connection %q: %v", ln.Address, conn.RemoteAddr(), err)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -309,7 +298,7 @@ func (ln *Listener) handle(conn net.Conn) error {
|
||||||
if err := tlsConn.Handshake(); err == io.EOF {
|
if err := tlsConn.Handshake(); err == io.EOF {
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return clientError{fmt.Errorf("TLS handshake failed: %v", err)}
|
return fmt.Errorf("TLS handshake failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := tlsConn.SetDeadline(time.Time{}); err != nil {
|
if err := tlsConn.SetDeadline(time.Time{}); err != nil {
|
||||||
return fmt.Errorf("failed to reset TLS handshake timeout: %v", err)
|
return fmt.Errorf("failed to reset TLS handshake timeout: %v", err)
|
||||||
|
@ -369,7 +358,7 @@ func (fe *Frontend) handle(downstream net.Conn, tlsState *tls.ConnectionState) e
|
||||||
defer upstream.Close()
|
defer upstream.Close()
|
||||||
|
|
||||||
if be.Proxy {
|
if be.Proxy {
|
||||||
h := proxyproto.HeaderProxyFromAddrs(byte(be.ProxyVersion), downstream.RemoteAddr(), downstream.LocalAddr())
|
h := proxyproto.HeaderProxyFromAddrs(2, downstream.RemoteAddr(), downstream.LocalAddr())
|
||||||
|
|
||||||
var tlvs []proxyproto.TLV
|
var tlvs []proxyproto.TLV
|
||||||
if tlsState.ServerName != "" {
|
if tlsState.ServerName != "" {
|
||||||
|
@ -393,17 +382,16 @@ func (fe *Frontend) handle(downstream net.Conn, tlsState *tls.ConnectionState) e
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := duplexCopy(upstream, downstream); err != nil {
|
if err := duplexCopy(upstream, downstream); err != nil {
|
||||||
return clientError{fmt.Errorf("failed to copy bytes: %v", err)}
|
return fmt.Errorf("failed to copy bytes: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
Network string
|
Network string
|
||||||
Address string
|
Address string
|
||||||
Proxy bool
|
Proxy bool
|
||||||
ProxyVersion int
|
TLSConfig *tls.Config // nil if no TLS
|
||||||
TLSConfig *tls.Config // nil if no TLS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func duplexCopy(a, b io.ReadWriter) error {
|
func duplexCopy(a, b io.ReadWriter) error {
|
||||||
|
|
|
@ -52,7 +52,7 @@ The following directives are supported:
|
||||||
*listen* <address>...
|
*listen* <address>...
|
||||||
Additional addresses to listen on.
|
Additional addresses to listen on.
|
||||||
|
|
||||||
*backend* <uri> { ... }
|
*backend* <uri>...
|
||||||
Backend to forward incoming connections to.
|
Backend to forward incoming connections to.
|
||||||
|
|
||||||
The following URIs are supported:
|
The following URIs are supported:
|
||||||
|
@ -64,25 +64,6 @@ The following directives are supported:
|
||||||
The _+proxy_ suffix can be added to the URI scheme to forward
|
The _+proxy_ suffix can be added to the URI scheme to forward
|
||||||
connection metadata via the PROXY protocol.
|
connection metadata via the PROXY protocol.
|
||||||
|
|
||||||
The backend directive supports the following sub-directives:
|
|
||||||
|
|
||||||
*tls_certfp* sha-256 <fingerprint>
|
|
||||||
Instead of using CAs to check the TLS certificate provided by the
|
|
||||||
backend, check that the certificate matches the provided
|
|
||||||
fingerprint. This can be used to connect to servers with a
|
|
||||||
self-signed certificate, for instance.
|
|
||||||
|
|
||||||
The fingerprint of a certificate can be obtained via *openssl*(1):
|
|
||||||
|
|
||||||
```
|
|
||||||
openssl x509 -fingerprint -sha256 -noout <certificate>
|
|
||||||
```
|
|
||||||
|
|
||||||
*proxy_version* <version>
|
|
||||||
PROXY protocol version to use, if _+proxy_ is specified.
|
|
||||||
The supported versions are 1 and 2.
|
|
||||||
If not specified, the PROXY version used defaults to version 2.
|
|
||||||
|
|
||||||
*tls* { ... }
|
*tls* { ... }
|
||||||
Customise frontend-specific TLS configuration.
|
Customise frontend-specific TLS configuration.
|
||||||
|
|
||||||
|
@ -142,13 +123,6 @@ The following directives are supported:
|
||||||
The environment will contain a *TLSTUNNEL_NAME* variable with the
|
The environment will contain a *TLSTUNNEL_NAME* variable with the
|
||||||
domain name to be validated.
|
domain name to be validated.
|
||||||
|
|
||||||
*acme_dns_command* command [arguments...]
|
|
||||||
Configure the ACME DNS challenge using the specified command.
|
|
||||||
|
|
||||||
The command must implement _deploy_challenge_ and _clean_challenge_
|
|
||||||
as specified by dehydrated's hooks:
|
|
||||||
https://github.com/dehydrated-io/dehydrated
|
|
||||||
|
|
||||||
# FILES
|
# FILES
|
||||||
|
|
||||||
_/etc/tlstunnel/config_
|
_/etc/tlstunnel/config_
|
||||||
|
|
Loading…
Reference in New Issue