// Command server is the host: it serves the admin web panel and acts as the // rendezvous point that NAT'd agents dial into over HTTP long-polling. // // TLS is terminated by nginx in front of this process, so it listens on plain // HTTP on localhost by default (see deploy/nginx.conf.example). package main import ( "flag" "log" "net/http" "os" "time" "github.com/x-grk/longpolling-remote-access/internal/server" ) func main() { addr := flag.String("addr", envOr("LPRA_ADDR", "127.0.0.1:8091"), "listen address (behind nginx)") dbPath := flag.String("db", envOr("LPRA_DB", "lpra.db"), "path to SQLite database") distDir := flag.String("dist", envOr("LPRA_DIST", "dist"), "directory with agent binaries served at /download/") tunnelAddr := flag.String("tunnel", envOr("LPRA_TUNNEL_ADDR", ":8446"), "listen address for the direct TCP+UDP forward tunnel (empty disables)") insecureCookies := flag.Bool("insecure-cookies", envOr("LPRA_INSECURE_COOKIES", "") == "1", "do not mark cookies Secure (plain-HTTP local testing only)") flag.Parse() db, err := server.OpenDB(*dbPath) if err != nil { log.Fatalf("open db: %v", err) } defer db.Close() srv, err := server.New(server.Options{ DB: db, DistDir: *distDir, SecureCookies: !*insecureCookies, TunnelAddr: *tunnelAddr, }) if err != nil { log.Fatalf("init server: %v", err) } httpSrv := &http.Server{ Addr: *addr, Handler: srv.Handler(), // No ReadTimeout/WriteTimeout: long-poll connections are intentionally // long-lived. nginx bounds them instead. ReadHeaderTimeout: 15 * time.Second, IdleTimeout: 130 * time.Second, } log.Printf("lpra server listening on %s (db=%s dist=%s)", *addr, *dbPath, *distDir) if err := httpSrv.ListenAndServe(); err != nil { log.Fatalf("serve: %v", err) } } func envOr(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def }