GolangNote

Golang笔记

Golang 实现的 Let’s Encrypt 验证响应handler

Permalink

简单的web 服务,响应Let’s Encrypt 域名所有者验证,不用 nginx 大器

Go: 响应Let’s Encrypt 域名所有者验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"flag"
	"log"
	"net/http"
)

func main() {
	var dir = flag.String("dir", ".", "folder")
	var port = flag.String("p", "80", "port")

	flag.Parse()

	log.Println("dir : ", *dir)
	log.Println("port : ", *port)

	staticHandler := http.StripPrefix("/.well-known/acme-challenge/", http.FileServer(http.Dir(*dir)))
	http.Handle("/.well-known/acme-challenge/", staticHandler)
	srv := &http.Server{Addr: ":" + *port}

	log.Fatal(srv.ListenAndServe())
}

更新

最新的 autocert 已经内置了这个请求响应

Go: HTTPHandler 调用
1
go http.ListenAndServe(":http", m.HTTPHandler(nil))

Go: 源码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
// It returns an http.Handler that responds to the challenges and must be
// running on port 80. If it receives a request that is not an ACME challenge,
// it delegates the request to the optional fallback handler.
//
// If fallback is nil, the returned handler redirects all GET and HEAD requests
// to the default TLS port 443 with 302 Found status code, preserving the original
// request path and query. It responds with 400 Bad Request to all other HTTP methods.
// The fallback is not protected by the optional HostPolicy.
//
// Because the fallback handler is run with unencrypted port 80 requests,
// the fallback should not serve TLS-only requests.
//
// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
// challenge for domain verification.
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
	m.challengeMu.Lock()
	defer m.challengeMu.Unlock()
	m.tryHTTP01 = true

	if fallback == nil {
		fallback = http.HandlerFunc(handleHTTPRedirect)
	}
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") {
			fallback.ServeHTTP(w, r)
			return
		}
		// A reasonable context timeout for cache and host policy only,
		// because we don't wait for a new certificate issuance here.
		ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
		defer cancel()
		if err := m.hostPolicy()(ctx, r.Host); err != nil {
			http.Error(w, err.Error(), http.StatusForbidden)
			return
		}
		data, err := m.httpToken(ctx, r.URL.Path)
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}
		w.Write(data)
	})
}

func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" && r.Method != "HEAD" {
		http.Error(w, "Use HTTPS", http.StatusBadRequest)
		return
	}
	target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
	http.Redirect(w, r, target, http.StatusFound)
}

func stripPort(hostport string) string {
	host, _, err := net.SplitHostPort(hostport)
	if err != nil {
		return hostport
	}
	return net.JoinHostPort(host, "443")
}

本文网址: https://golangnote.com/topic/221.html 转摘请注明来源

Related articles

Write a Comment to "Golang 实现的 Let’s Encrypt 验证响应handler"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.18 Processed in 0ms