better-argo-tunnels/cmd/client/main.go

85 lines
2.1 KiB
Go

package main
import (
"log"
"os"
"strconv"
"time"
"github.com/nixc/reverse-ssh-traefik/internal/client"
)
func envRequired(key string) string {
v := os.Getenv(key)
if v == "" {
log.Fatalf("Required environment variable %s is not set", key)
}
return v
}
func envOr(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Println("tunnel-client starting")
serverAddr := envRequired("TUNNEL_SERVER")
domain := envRequired("TUNNEL_DOMAIN")
keyPath := envOr("TUNNEL_KEY", "/keys/id_ed25519")
// Optional HTTP Basic Auth credentials for Traefik middleware.
authUser := envOr("TUNNEL_AUTH_USER", "")
authPass := envOr("TUNNEL_AUTH_PASS", "")
localPortStr := envOr("TUNNEL_PORT", "8080")
localPort, err := strconv.Atoi(localPortStr)
if err != nil {
log.Fatalf("Invalid TUNNEL_PORT=%q: %v", localPortStr, err)
}
// Load the private key.
signer, err := client.LoadPrivateKey(keyPath)
if err != nil {
log.Fatalf("Failed to load private key: %v", err)
}
log.Printf("Loaded key from %s", keyPath)
// Reconnect loop.
backoff := time.Second
maxBackoff := 30 * time.Second
for {
if authUser != "" {
log.Printf("Connecting to %s (domain=%s, local_port=%d, basicauth=enabled)", serverAddr, domain, localPort)
} else {
log.Printf("Connecting to %s (domain=%s, local_port=%d)", serverAddr, domain, localPort)
}
sshClient, err := client.Connect(serverAddr, signer)
if err != nil {
log.Printf("Connection failed: %v (retry in %s)", err, backoff)
time.Sleep(backoff)
backoff = min(backoff*2, maxBackoff)
continue
}
// Reset backoff on successful connection.
backoff = time.Second
log.Printf("Connected to %s", serverAddr)
// Set up the reverse tunnel (blocks until disconnected).
if err := client.SetupTunnel(sshClient, domain, localPort, authUser, authPass); err != nil {
log.Printf("Tunnel error: %v (reconnecting in %s)", err, backoff)
}
sshClient.Close()
time.Sleep(backoff)
backoff = min(backoff*2, maxBackoff)
}
}