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

77 lines
1.7 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")
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 {
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); err != nil {
log.Printf("Tunnel error: %v (reconnecting in %s)", err, backoff)
}
sshClient.Close()
time.Sleep(backoff)
backoff = min(backoff*2, maxBackoff)
}
}