Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 718fc3922e | |||
| db6baaf7dc | |||
| f5846dcd12 | |||
| f8a9ad40b3 | |||
| 23bf0ff34c | |||
| c28d6e3675 | |||
| 5907a46658 | |||
| 37ede71813 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1 @@
|
||||
./server
|
||||
server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 marco@sdf.org
|
||||
Copyright (c) marco@sdf.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
2
Makefile
2
Makefile
@@ -4,7 +4,6 @@ GOOS := plan9
|
||||
GOARCH := amd64
|
||||
|
||||
test:
|
||||
SDF_PROXY_ALLOWED_HOSTS=teapot-dummy-target.example.com \
|
||||
go test -v
|
||||
|
||||
build: test
|
||||
@@ -13,3 +12,4 @@ build: test
|
||||
|
||||
deploy: build
|
||||
rsync -avz server iceland.sdf.org:html/pub/
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
An http server to which one or more domains can be pointed to.
|
||||
Incoming requests will be proxied to an arbitrary target http server, like Amazon S3, Blogger.com or one of the many options available at sdf.org.
|
||||
|
||||
The main idea is to have a server which requires no configuration, handles TLS and can run on mostly any host on the internet with an IP address in one's possession.
|
||||
The main goal is to serve content for a domain via a server which requires no configuration, handles TLS and can run on mostly any host on the internet with an IP address in one's possession.
|
||||
Obviously this solution is an end in itself and there already is [Caddy](https://caddyserver.com/).
|
||||
|
||||
Thanks to [golang.org/x/crypto/acme/autocert](https://pkg.go.dev/golang.org/x/crypto/acme/autocert), the server will automatically attempt to get a certificate from Let's Encrypt via the [HTTP-01 challenge](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) to enable TLS.
|
||||
@@ -23,6 +23,7 @@ $ ./server
|
||||
```
|
||||
|
||||
## Future Ideas
|
||||
|
||||
- Support for rewriting URL paths
|
||||
- Configuration option to keep keys and TLS certificates in memory only
|
||||
- Support for [cgi-bin](https://pkg.go.dev/net/http/cgi) and/or [FastCGI](https://pkg.go.dev/net/http/fcgi)
|
||||
|
||||
8
go.mod
8
go.mod
@@ -2,11 +2,9 @@ module server
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.4.0
|
||||
)
|
||||
require golang.org/x/crypto v0.6.0
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
)
|
||||
|
||||
14
go.sum
14
go.sum
@@ -1,8 +1,6 @@
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
|
||||
20
server.go
20
server.go
@@ -34,6 +34,9 @@ var (
|
||||
|
||||
func init() {
|
||||
setMyIpAndPtrAddr(&myIp, &myPtrAddr)
|
||||
if len(myPtrAddr) > 0 {
|
||||
tlsCertManager.HostPolicy = autocert.HostWhitelist(append(allowedHosts, myPtrAddr)...)
|
||||
}
|
||||
}
|
||||
|
||||
// setMyIpAndPtrAddr attempts to set myIp and myPtrAddr
|
||||
@@ -75,7 +78,10 @@ func newHttpReverseProxy(addr string, serveTls bool) *httpReverseProxy {
|
||||
server.Addr = addr
|
||||
server.serveTls = serveTls
|
||||
if server.serveTls {
|
||||
server.TLSConfig = &tls.Config{GetCertificate: tlsCertManager.GetCertificate}
|
||||
server.TLSConfig = &tls.Config{
|
||||
GetCertificate: tlsCertManager.GetCertificate,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
}
|
||||
|
||||
proxy := new(httputil.ReverseProxy)
|
||||
@@ -91,7 +97,7 @@ func newHttpReverseProxy(addr string, serveTls bool) *httpReverseProxy {
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
// Hostnames specified in the variable allowedHosts for which the reverse proxy should direct requests to the target host
|
||||
// Hostnames for which the reverse proxy should direct requests to the target host
|
||||
for _, host := range allowedHosts {
|
||||
mux.Handle(host+"/", proxy)
|
||||
mux.Handle(host+"/.well-known/acme-challenge/", tlsCertManager.HTTPHandler(nil))
|
||||
@@ -122,15 +128,17 @@ func newHttpReverseProxy(addr string, serveTls bool) *httpReverseProxy {
|
||||
|
||||
// listenAndServe will call ListenAndServe or ListenAndServeTLS on httpReverseProxy to handle requests on incoming connections
|
||||
func (t *httpReverseProxy) listenAndServe() {
|
||||
fmt.Printf("Listening on %s\n", t.Addr)
|
||||
var err error
|
||||
|
||||
fmt.Printf("Listening on %s\n", t.Addr)
|
||||
|
||||
if t.serveTls {
|
||||
err = t.ListenAndServeTLS("", "")
|
||||
} else {
|
||||
err = t.ListenAndServe()
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("listenAndServe, Addr: %s, serveTls: %s, error: %s", t.Addr, strconv.FormatBool(t.serveTls), err)
|
||||
log.Fatalf("listenAndServe, Addr: %s, serveTls: %s, error: %v", t.Addr, strconv.FormatBool(t.serveTls), err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,10 +147,6 @@ func main() {
|
||||
log.Fatalf("Invalid Let's Encrypt account email: %v\n", err)
|
||||
}
|
||||
|
||||
if len(myPtrAddr) > 0 {
|
||||
tlsCertManager.HostPolicy = autocert.HostWhitelist(append(allowedHosts, myPtrAddr)...)
|
||||
}
|
||||
|
||||
fmt.Print("Allowed hosts: ")
|
||||
fmt.Println(allowedHosts)
|
||||
fmt.Print("PTR record (if any): ")
|
||||
|
||||
@@ -7,6 +7,10 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func init() {
|
||||
allowedHosts = []string{"teapot-dummy-target.example.com"}
|
||||
}
|
||||
|
||||
func TestHttpReverseProxy(t *testing.T) {
|
||||
var header map[string][]string
|
||||
|
||||
@@ -56,20 +60,21 @@ func TestHttpReverseProxy(t *testing.T) {
|
||||
response := httptest.NewRecorder()
|
||||
reverseProxy.Handler.ServeHTTP(response, request)
|
||||
|
||||
got := header
|
||||
gotHeader := header
|
||||
header = nil
|
||||
|
||||
assertStatus(t, response.Code, test.wantResponseCode)
|
||||
assertHeader(t, got, "X-Forwarded-Host", test.wantXForwardedHostHeader)
|
||||
if len(test.wantXForwardedHostHeader) > 0 {
|
||||
assertHeader(t, gotHeader, "X-Forwarded-Host", test.wantXForwardedHostHeader)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func assertHeader(t *testing.T, gotHeader map[string][]string, headerName, want string) {
|
||||
t.Helper()
|
||||
got := ""
|
||||
lookup, ok := gotHeader[headerName]
|
||||
if ok {
|
||||
var got string
|
||||
if lookup, ok := gotHeader[headerName]; ok {
|
||||
got = lookup[0]
|
||||
}
|
||||
if got != want {
|
||||
|
||||
Reference in New Issue
Block a user