102 lines
2.7 KiB
Go
102 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
"github.com/nixc/reverse-ssh-traefik/internal/server"
|
|
)
|
|
|
|
func envOr(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func envRequired(key string) string {
|
|
v := os.Getenv(key)
|
|
if v == "" {
|
|
log.Fatalf("Required environment variable %s is not set", key)
|
|
}
|
|
return v
|
|
}
|
|
|
|
func envInt(key string, fallback int) int {
|
|
v := os.Getenv(key)
|
|
if v == "" {
|
|
return fallback
|
|
}
|
|
n, err := strconv.Atoi(v)
|
|
if err != nil {
|
|
log.Printf("WARN: invalid %s=%q, using default %d", key, v, fallback)
|
|
return fallback
|
|
}
|
|
return n
|
|
}
|
|
|
|
func main() {
|
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
|
log.Println("tunnel-server starting")
|
|
|
|
// SSH server config (for accepting tunnel clients).
|
|
sshPort := envOr("SSH_PORT", "2222")
|
|
hostKeyPath := envOr("SSH_HOST_KEY", "/keys/host_key")
|
|
authKeysPath := envOr("AUTHORIZED_KEYS", "/keys/authorized_keys")
|
|
portStart := envInt("PORT_RANGE_START", 10000)
|
|
portEnd := envInt("PORT_RANGE_END", 10100)
|
|
|
|
// Remote Traefik host config (SSH into the ingress host to manage routes).
|
|
traefikHost := envRequired("TRAEFIK_SSH_HOST")
|
|
traefikUser := envOr("TRAEFIK_SSH_USER", "root")
|
|
traefikKey := envRequired("TRAEFIK_SSH_KEY")
|
|
traefikConfigDir := envOr("TRAEFIK_CONFIG_DIR", "/root/traefik/dynamic")
|
|
entrypoint := envOr("TRAEFIK_ENTRYPOINT", "websecure")
|
|
certResolver := envOr("TRAEFIK_CERT_RESOLVER", "letsencryptresolver")
|
|
|
|
// Load the SSH key for connecting to the Traefik host.
|
|
traefikSigner, err := server.LoadSigner(traefikKey)
|
|
if err != nil {
|
|
log.Fatalf("Failed to load Traefik SSH key: %v", err)
|
|
}
|
|
log.Printf("Loaded Traefik host SSH key")
|
|
|
|
// Initialize port pool.
|
|
pool := server.NewPortPool(portStart, portEnd)
|
|
log.Printf("Port pool: %d-%d (%d ports)", portStart, portEnd, portEnd-portStart+1)
|
|
|
|
// Initialize Traefik label manager (remote SSH).
|
|
labels, err := server.NewLabelManager(
|
|
traefikHost, traefikUser, traefikSigner,
|
|
traefikConfigDir, entrypoint, certResolver,
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("Failed to init label manager: %v", err)
|
|
}
|
|
defer labels.Close()
|
|
|
|
// Initialize SSH server for tunnel clients.
|
|
sshSrv, err := server.NewSSHServer(hostKeyPath, authKeysPath, pool, labels)
|
|
if err != nil {
|
|
log.Fatalf("Failed to init SSH server: %v", err)
|
|
}
|
|
|
|
// Handle graceful shutdown.
|
|
sigCh := make(chan os.Signal, 1)
|
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
|
go func() {
|
|
sig := <-sigCh
|
|
log.Printf("Received signal %s, shutting down", sig)
|
|
os.Exit(0)
|
|
}()
|
|
|
|
// Start SSH server.
|
|
addr := "0.0.0.0:" + sshPort
|
|
if err := sshSrv.ListenAndServe(addr); err != nil {
|
|
log.Fatalf("SSH server error: %v", err)
|
|
}
|
|
}
|