package main import ( "context" "crypto/tls" "fmt" "io" "log" "net/http" "os" "github.com/pion/webtransport" "github.com/quic-go/quic-go/http3" ) func main() { // 1. Настройка TLS (обязательно для WebTransport/QUIC) // Поскольку SSL терминация на VPS, здесь мы используем самоподписанный сертификат // для внутренней связи (Dokploy <-> Caddy). Nixpacks соберет это. // Но для простоты примера мы просто слушаем обычный HTTP, так как Caddy проксирует. // ОДНАКО: WebTransport ТРЕБУЕТ TLS. Внутренний TLS тоже нужен. // Мы сгенерируем его на лету, чтобы не возиться с файлами. cert, err := generateSelfSignedCert() if err != nil { log.Fatal(err) } tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, NextProtos: []string{"h3"}, // HTTP/3 } // 2. Настройка WebTransport Handler server := webtransport.Server{ H3: http3.Server{ Addr: ":8080", // Порт внутри контейнера TLSConfig: tlsConfig, }, CheckOrigin: func(r *http.Request) bool { return true }, // Разрешить все Origin для теста } // Раздаем index.html http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "index.html") }) http.HandleFunc("/wt", func(w http.ResponseWriter, r *http.Request) { log.Println("New WebTransport request from:", r.RemoteAddr) sess, err := server.Upgrade(w, r) if err != nil { log.Printf("Upgrade failed: %v", err) return } // Обработка сессии в отдельной горутине go handleSession(sess) }) log.Println("WebTransport server listening on https://localhost:8080/wt (via Caddy)") // Запускаем HTTP/3 сервер if err := server.ListenAndServe(); err != nil { log.Fatal(err) } } // Обработка одной WebTransport сессии func handleSession(sess *webtransport.Session) { defer sess.CloseWithError(0, "session closed") for { // Читаем датаграммы (самый быстрый и ненадежный способ, как UDP) msg, err := sess.ReadDatagram(context.Background()) if err != nil { if err != io.EOF { log.Printf("ReadDatagram error: %v", err) } return } fmt.Printf("Received Datagram from %v: %s\n", sess.RemoteAddr(), string(msg)) } } // Вспомогательная функция для генерации внутреннего SSL // (Для связи Caddy -> Dokploy по Wireguard) import ( "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" "time" ) func generateSelfSignedCert() (tls.Certificate, error) { priv, _ := rsa.GenerateKey(rand.Reader, 2048) template := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{Organization: []string{"Pion WebTransport Test"}}, NotBefore: time.Now(), NotAfter: time.Now().Add(time.Hour * 24 * 365), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) return tls.X509KeyPair(certPEM, keyPEM) }