# Packages
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
# README
use as library
- dns
- http01
- tlsalpn1
acme prod
HTTP-01:通过HTTP访问服务器80端口的/.well-known/acme-challenge验证。
DNS-01:在DNS中添加_acme-challenge开头的TXT记录,这种方式因为能签发通配符证书(Wildcard)而被大范围使用。
TLS-SNI-01、TLS-ALPN-01:通过TLS的方式对443端口访问进行验证。(TLS-ALPN-01支持的客户端非常少,TLS-SNI因为漏洞被遗弃)
tls
占用443端口,需要从从连接上拿到临时证书,然后监听,从这个tls上获取证书;或者通过获取现有证书从tls连接上验证并获取新证书
http
占用80,交互只涉及到http固定目录,设随机码校验,校验通过,可以获取证书;也可以在nginx配置验证路由,在golang里面obtain证书
server {
listen 80 default_server;
root /usr/local/nginx/html;
location / {
return 404;
}
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
}
location = /.well-known/acme-challenge/ {
return 404;
}
dns
不占端口,需要知道dns厂商,需要在dns服务器做txt记录,但是可以获取泛域名证书
usage
- http01方式
// demo1
import "github.com/bugfan/acme"
type H struct {}
func (h *H) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("your http.handler", r.URL.String())
// todo something
}
func main(){
h := &H{}
p := acme.NewHTTP01Provider(h)
a, err := acme.NewACME("youremail")
if err != nil {
fmt.Println("new error:", err)
return
}
a.SetHTTP01Provider(p)
cert, err := a.Obtain("app.xxx.cn")
if err != nil {
fmt.Println("obtain result:", err)
return
}
fmt.Println("obtain result:", cert.Key, cert.Cert, cert.Intermediate)
}
// demo2
import "github.com/bugfan/acme"
type H struct {}
func (h *H) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("your http.handler", r.URL.String())
// todo something
}
func main(){
h := &H{}
p := acme.NewHTTP01Provider(h)
a, err := acme.NewACME("youremail")
if err != nil {
fmt.Println("new error:", err)
return
}
// a.SetHTTP01Provider(p) // not set
cert, err := a.Obtain("app.xxx.cn")
if err != nil {
fmt.Println("obtain result:", err)
return
}
fmt.Println("obtain result:", cert.Key, cert.Cert, cert.Intermediate)
http.ListenAndServe(":80", nil) // if not set,should you to listen at '80'
}
- tlsalpn1方式
// demo1 你的服务没有占用443(显然这种情况比较少)
import "github.com/bugfan/acme"
func main(){
a, err := acme.NewACME("[email protected]")
if err != nil {
fmt.Println("new error:", err)
return
}
tp := acme.NewDefaultTLSALPN01Provider()
a.SetTLSALPN01Provider(tp)
cert, err := a.Obtain("app.xxx.cn")
if err != nil {
fmt.Println("obtain result:", err)
return
}
fmt.Println("obtain result:", cert.Key, cert.Cert, cert.Intermediate)
}
// demo2 你的服务占用了443
import "github.com/bugfan/acme"
var myacme acme.ACME
func init() {
var err error
myacme, err = acme.NewACME("[email protected]")
if err != nil {
fmt.Println("new acme error:", err)
}
}
func main() {
// ...
go func() {
getYourHTTPSServer().ListenAndServeTLS("your-cert-filt-path", "your-key-file-path")
}()
go func() {
time.Sleep(5e9) // or if when you need obtain
cert, err := myacme.Obtain("app.xxx.cn")
if err != nil {
fmt.Println("obtain result:", err)
return
}
fmt.Println("obtain result:", cert.Key, cert.Cert, cert.Intermediate)
}()
// ...
<-chan int(nil)
}
func getYourHTTPSServer() *http.Server {
tlsConf := &tls.Config{}
handler := &H{}
/*
* one of the following ways is ok
*/
// demo1 Certificates()
// certProvider := handler
//demo2 GetCertificate(*tls.ClientHelloInfo)
certProvider := handler
//demo3 GetConfigForClient(*tls.ClientHelloInfo)
// certProvider := handler
tc, err := acme.NewACMETLSConfig(tlsConf, certProvider)
if err != nil {
fmt.Println("NewACMETLSConfig error:", err)
panic(err) // or tc=tlsConf
}
return &http.Server{
Handler: handler,
TLSConfig: tc,
Addr: ":443",
}
}
type H struct{}
func (h *H) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Println("your http.handler", r.URL.String())
// todo something
}
func (h *H) Certificates() []*tls.Certificate {
certs := make([]*tls.Certificate, 0)
certs = append(certs, h.Cert())
return certs
}
func (h *H) Cert() *tls.Certificate {
// need read from your cert file
yourcert, _ := tls.X509KeyPair([]byte(fmt.Sprintf("%s\n%s", "your cert data", "your intermediate data")), []byte("your key"))
return &yourcert
}
var ServerIP string = "212.45.32.55" // your server ip
func (h *H) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if hello.ServerName == ServerIP {
return h.Cert(), nil
}
return nil, nil
}
some issue
- http 没有备案被云厂商拦截了
[app.xxx.cn] acme: error: 403 :: urn:ietf:params:acme:error:unauthorized :: During secondary validation: Invalid response from https://dnspod.qcloud.com/static/webblock.html?d=app.xxx.cn [203.205.224.59]: "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n\t\t<", url:
- tls 不是tls的监听在443
root@VM-0-10-ubuntu:/home# ./acem
2021/03/10 18:20:31 [INFO] acme: Registering account for [email protected]
2021/03/10 18:20:32 [INFO] [www.xxxx.cn] acme: Obtaining bundled SAN certificate
2021/03/10 18:20:32 [INFO] [www.xxxx.cn] AuthURL: https://acme-v02.api.letsencrypt.org/acme/authz-v3/11452689397
2021/03/10 18:20:32 [INFO] [www.xxxx.cn] acme: use tls-alpn-01 solver
2021/03/10 18:20:32 [INFO] [www.xxxx.cn] acme: Trying to solve TLS-ALPN-01
2021/03/10 18:20:39 [INFO] Unable to deactivate the authorization: https://acme-v02.api.letsencrypt.org/acme/authz-v3/11452689397
2021/03/10 18:20:39 acme: Error -> One or more domains had a problem:
[www.xxxx.cn] acme: error: 400 :: urn:ietf:params:acme:error:malformed :: Server only speaks HTTP, not TLS, url:
- tls 443没起
// 443没监听
2021/03/20 22:32:57 Unable to deactivate the authorization: https://acme-v02.api.letsencrypt.org/acme/authz-v3/11705545896
obtain result2: error: one or more domains had a problem:
[www.xxxx.cn] acme: error: 400 :: urn:ietf:params:acme:error:connection :: Connection refused
- tls 这是tls层的tls.config配置缺东西
// tls server tlsconfig配置缺东西
%w tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config
- rate 这是签发次数太多了
2021/03/21 19:12:14 [app.xxx.cn] acme: Obtaining bundled SAN certificate
obtain result2: acme: error: 429 :: POST :: https://acme-v02.api.letsencrypt.org/acme/new-order :: urn:ietf:params:acme:error:rateLimited :: Error creating new order :: too many certificates already issued for exact set of domains: app.xxx.cn: see https://letsencrypt.org/docs/rate-limits/
- 解析不对
www.xxx.cn 签发失败: get directory at 'https://acme-v02.api.letsencrypt.org/directory': Get "https://acme-v02.api.letsencrypt.org/directory": dial tcp: lookup acme-v02.api.letsencrypt.org on 127.0.0.11:53: server misbehaving
解析不对,进入app这个容器(或者主机)内部,执行 echo '172.65.32.248 acme-v02.api.letsencrypt.org' > /etc/hosts