Skip to content

Commit 10b4cd0

Browse files
authored
Add ability to autogenerate & serve LetsEncrypt SSL/TLS Certificate (#4)
This change uses the autocert package to add initial support for generating and serving a real live SSL certificate from LetsEncrypt via `ssl-proxy`. Now, serving your application with SSL is as easy as: ```sh ./ssl-proxy -from=0.0.0.0:443 -to=localhost:8080 -domain=mydomain.com ``` this will attempt to fetch a certificate for mydomain.com from LetsEncrypt (port 443 must be bindable by this process) and then begin proxying HTTPS traffic on :443 to any server running on :8080. Easy. This closes #1.
1 parent 5f303c7 commit 10b4cd0

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

Gopkg.lock

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Gopkg.toml example
2+
#
3+
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
4+
# for detailed Gopkg.toml documentation.
5+
#
6+
# required = ["github.com/user/thing/cmd/thing"]
7+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+
#
9+
# [[constraint]]
10+
# name = "github.com/user/project"
11+
# version = "1.0.0"
12+
#
13+
# [[constraint]]
14+
# name = "github.com/user/project2"
15+
# branch = "dev"
16+
# source = "github.com/myfork/project2"
17+
#
18+
# [[override]]
19+
# name = "github.com/x/y"
20+
# version = "2.4.0"
21+
#
22+
# [prune]
23+
# non-go = false
24+
# go-tests = true
25+
# unused-packages = true
26+
27+
28+
[[constraint]]
29+
branch = "master"
30+
name = "golang.org/x/crypto"
31+
32+
[prune]
33+
go-tests = true
34+
unused-packages = true

main.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ import (
1212
"strings"
1313

1414
"github.com/suyashkumar/ssl-proxy/gen"
15+
"golang.org/x/crypto/acme/autocert"
1516
)
1617

1718
var (
1819
to = flag.String("to", "http://127.0.0.1:80", "the address and port for which to proxy requests to")
1920
fromURL = flag.String("from", "127.0.0.1:4430", "the tcp address and port this proxy should listen for requests on")
2021
certFile = flag.String("cert", "", "path to a tls certificate file. If not provided, ssl-proxy will generate one for you in ~/.ssl-proxy/")
2122
keyFile = flag.String("key", "", "path to a private key file. If not provided, ssl-proxy will generate one for you in ~/.ssl-proxy/")
23+
domain = flag.String("domain", "", "domain to mint letsencrypt certificates for. Usage of this parameter implies acceptance of the LetsEncrypt terms of service.")
2224
)
2325

2426
const (
@@ -31,7 +33,12 @@ const (
3133
func main() {
3234
flag.Parse()
3335

34-
if *certFile == "" || *keyFile == "" {
36+
validCertFile := *certFile != ""
37+
validKeyFile := *keyFile != ""
38+
validDomain := *domain != ""
39+
40+
// Determine if we need to generate self-signed certs
41+
if (!validCertFile || !validKeyFile) && !validDomain {
3542
// Use default file paths
3643
*certFile = DefaultCertFile
3744
*keyFile = DefaultKeyFile
@@ -66,13 +73,40 @@ func main() {
6673
log.Println("Assuming -to URL is using http://")
6774
}
6875

76+
// Parse toURL as a URL
6977
toURL, err := url.Parse(*to)
7078
if err != nil {
7179
log.Fatal("Unable to parse 'to' url: ", err)
7280
}
7381

82+
// Setup ServeMux
7483
localProxy := httputil.NewSingleHostReverseProxy(toURL)
75-
http.Handle("/", localProxy)
84+
mux := http.NewServeMux()
85+
mux.Handle("/", localProxy)
86+
7687
log.Printf("Proxying calls from https://%s (SSL/TLS) to %s", *fromURL, toURL)
77-
log.Fatal(http.ListenAndServeTLS(*fromURL, *certFile, *keyFile, nil))
88+
89+
// Determine if we should serve with autogenerated LetsEncrypt certificates or not
90+
if validDomain {
91+
// Domain is present, use autocert
92+
// TODO: validate domain (though, autocert may do this)
93+
// TODO: for some reason this seems to only work on :443
94+
log.Printf("Domain specified, using LetsEncrypt to autogenerate and serve certs for %s\n", *domain)
95+
if !strings.HasSuffix(*fromURL, ":443") {
96+
log.Println("WARN: Right now, you must serve on port :443 to use autogenerated LetsEncrypt certs using the -domain flag, this may NOT WORK")
97+
}
98+
m := &autocert.Manager{
99+
Cache: autocert.DirCache("certs"),
100+
Prompt: autocert.AcceptTOS,
101+
HostPolicy: autocert.HostWhitelist(*domain),
102+
}
103+
s := &http.Server{
104+
Addr: *fromURL,
105+
TLSConfig: m.TLSConfig(),
106+
}
107+
s.Handler = mux
108+
s.ListenAndServeTLS("", "")
109+
} else {
110+
log.Fatal(http.ListenAndServeTLS(*fromURL, *certFile, *keyFile, mux))
111+
}
78112
}

0 commit comments

Comments
 (0)