mirror of
https://github.com/yusing/godoxy.git
synced 2025-07-16 02:04:04 +02:00
initial autocert support, readme update
This commit is contained in:
parent
22f911c30f
commit
e7f6abf027
14 changed files with 515 additions and 75 deletions
40
README.md
40
README.md
|
@ -13,6 +13,9 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
- [Configuration](#configuration)
|
- [Configuration](#configuration)
|
||||||
- [Labels](#labels)
|
- [Labels](#labels)
|
||||||
- [Environment Variables](#environment-variables)
|
- [Environment Variables](#environment-variables)
|
||||||
|
- [Config File](#config-file)
|
||||||
|
- [Provider File](#provider-file)
|
||||||
|
- [Supported Cert Providers](#supported-cert-providers)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
- [Single Port Configuration](#single-port-configuration-example)
|
- [Single Port Configuration](#single-port-configuration-example)
|
||||||
- [Multiple Ports Configuration](#multiple-ports-configuration-example)
|
- [Multiple Ports Configuration](#multiple-ports-configuration-example)
|
||||||
|
@ -22,7 +25,6 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
- [Benchmarks](#benchmarks)
|
- [Benchmarks](#benchmarks)
|
||||||
- [Memory usage](#memory-usage)
|
- [Memory usage](#memory-usage)
|
||||||
- [Build it yourself](#build-it-yourself)
|
- [Build it yourself](#build-it-yourself)
|
||||||
- [Getting SSL certs](#getting-ssl-certs)
|
|
||||||
|
|
||||||
## Key Points
|
## Key Points
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
- auto detect reverse proxies from docker
|
- auto detect reverse proxies from docker
|
||||||
- additional reverse proxies from provider yaml file
|
- additional reverse proxies from provider yaml file
|
||||||
- allow multiple docker / file providers by custom `config.yml` file
|
- allow multiple docker / file providers by custom `config.yml` file
|
||||||
|
- auto certificate obtaining and renewal (See [Config File](#config-file) and [Supported Cert Providers](#supported-cert-providers))
|
||||||
- subdomain matching **(domain name doesn't matter)**
|
- subdomain matching **(domain name doesn't matter)**
|
||||||
- path matching
|
- path matching
|
||||||
- HTTP proxy
|
- HTTP proxy
|
||||||
|
@ -37,6 +40,7 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
- HTTP round robin load balance support (same subdomain and path across different hosts)
|
- HTTP round robin load balance support (same subdomain and path across different hosts)
|
||||||
- Auto hot-reload on container start / die / stop or config changes.
|
- Auto hot-reload on container start / die / stop or config changes.
|
||||||
- Simple panel to see all reverse proxies and health (visit port [panel port] of go-proxy `https://*.y.z:[panel port]`)
|
- Simple panel to see all reverse proxies and health (visit port [panel port] of go-proxy `https://*.y.z:[panel port]`)
|
||||||
|
- you can customize it by modifying [templates/panel.html](templates/panel.html)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -52,7 +56,7 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
|
|
||||||
### Binary
|
### Binary
|
||||||
|
|
||||||
1. (Optional) Prepare your certificates in `certs/` to enable https. See [Getting SSL Certs](#getting-ssl-certs)
|
1. (Optional) Prepare your wildcard (`*.y.z`) SSL cert in `certs/` to enable https. See [Getting SSL Certs](#getting-ssl-certs)
|
||||||
|
|
||||||
- cert / chain / fullchain: `./certs/cert.crt`
|
- cert / chain / fullchain: `./certs/cert.crt`
|
||||||
- private key: `./certs/priv.key`
|
- private key: `./certs/priv.key`
|
||||||
|
@ -67,7 +71,7 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
|
|
||||||
2. Add networks to make sure it is in the same network with other containers, or make sure `proxy.<alias>.host` is reachable
|
2. Add networks to make sure it is in the same network with other containers, or make sure `proxy.<alias>.host` is reachable
|
||||||
|
|
||||||
3. (Optional) Mount your SSL certs to enable https. See [Getting SSL Certs](#getting-ssl-certs)
|
3. (Optional) Mount your wildcard (`*.y.z`) SSL cert to enable https. See [Getting SSL Certs](#getting-ssl-certs)
|
||||||
|
|
||||||
- cert / chain / fullchain -> `/app/certs/cert.crt`
|
- cert / chain / fullchain -> `/app/certs/cert.crt`
|
||||||
- private key -> `/app/certs/priv.key`
|
- private key -> `/app/certs/priv.key`
|
||||||
|
@ -110,8 +114,8 @@ With container name, most of the time no label needs to be added.
|
||||||
- http/https: defaults to first expose port (declared in `Dockerfile` or `docker-compose.yml`)
|
- http/https: defaults to first expose port (declared in `Dockerfile` or `docker-compose.yml`)
|
||||||
- tcp/udp: is in format of `[<listeningPort>:]<targetPort>`
|
- tcp/udp: is in format of `[<listeningPort>:]<targetPort>`
|
||||||
- when `listeningPort` is omitted (not suggested), a free port will be used automatically.
|
- when `listeningPort` is omitted (not suggested), a free port will be used automatically.
|
||||||
- `targetPort` must be a number, or the predefined names (see [stream.go](src/go-proxy/stream.go#L28))
|
- `targetPort` must be a number, or the predefined names (see [constants.go:14](src/go-proxy/constants.go#L14))
|
||||||
- `no_tls_verify`: whether skip tls verify when scheme is https
|
- `proxy.<alias>.no_tls_verify`: whether skip tls verify when scheme is https
|
||||||
- defaults to false
|
- defaults to false
|
||||||
- `proxy.<alias>.path`: path matching (for http proxy only)
|
- `proxy.<alias>.path`: path matching (for http proxy only)
|
||||||
- defaults to empty
|
- defaults to empty
|
||||||
|
@ -136,6 +140,26 @@ With container name, most of the time no label needs to be added.
|
||||||
- `GOPROXY_DEBUG`: set to `1` or `true` to enable debug behaviors (i.e. output, etc.)
|
- `GOPROXY_DEBUG`: set to `1` or `true` to enable debug behaviors (i.e. output, etc.)
|
||||||
- `GOPROXY_REDIRECT_HTTP`: set to `0` or `false` to disable http to https redirect (only when certs are located)
|
- `GOPROXY_REDIRECT_HTTP`: set to `0` or `false` to disable http to https redirect (only when certs are located)
|
||||||
|
|
||||||
|
### Config File
|
||||||
|
|
||||||
|
See [config.example.yml](config.example.yml)
|
||||||
|
|
||||||
|
### Provider File
|
||||||
|
|
||||||
|
See [providers.example.yml](providers.example.yml)
|
||||||
|
|
||||||
|
### Supported cert providers
|
||||||
|
|
||||||
|
- Cloudflare
|
||||||
|
```yaml
|
||||||
|
autocert:
|
||||||
|
...
|
||||||
|
options:
|
||||||
|
auth_token: "YOUR_ZONE_API_TOKEN"
|
||||||
|
```
|
||||||
|
|
||||||
|
Follow [this guide](https://cloudkul.com/blog/automcatic-renew-and-generate-ssl-on-your-website-using-lego-client/) to create a new token with `Zone.DNS` read and edit permissions
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Single port configuration example
|
### Single port configuration example
|
||||||
|
@ -334,10 +358,6 @@ It takes ~30 MB for 50 proxy entries
|
||||||
|
|
||||||
3. build binary with `make build`
|
3. build binary with `make build`
|
||||||
|
|
||||||
4. start your container with `docker compose up -d`
|
4. start your container with `make up` (docker) or `bin/go-proxy` (binary)
|
||||||
|
|
||||||
## Getting SSL certs
|
|
||||||
|
|
||||||
I personally use `nginx-proxy-manager` to get SSL certs with auto renewal by Cloudflare DNS challenge. You may symlink the certs from `nginx-proxy-manager` to `certs/` folder relative to project root. (For docker) mount them to `go-proxy`'s `/app/certs`
|
|
||||||
|
|
||||||
[panel port]: 8443
|
[panel port]: 8443
|
||||||
|
|
BIN
bin/go-proxy
BIN
bin/go-proxy
Binary file not shown.
|
@ -1,3 +1,11 @@
|
||||||
|
# uncomment to use autocert
|
||||||
|
# autocert:
|
||||||
|
# email: "user@y.z" # email for acme certificate
|
||||||
|
# domains:
|
||||||
|
# - "*.y.z" # domain for acme certificate, use wild card to allow all subdomains
|
||||||
|
# provider: cloudflare
|
||||||
|
# options:
|
||||||
|
# auth_token: "YOUR_ZONE_API_TOKEN"
|
||||||
providers:
|
providers:
|
||||||
local:
|
local:
|
||||||
kind: docker
|
kind: docker
|
10
go.mod
10
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/docker/cli v26.0.0+incompatible
|
github.com/docker/cli v26.0.0+incompatible
|
||||||
github.com/docker/docker v26.0.0+incompatible
|
github.com/docker/docker v26.0.0+incompatible
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
|
github.com/go-acme/lego/v4 v4.16.1
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
golang.org/x/net v0.22.0
|
golang.org/x/net v0.22.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
@ -13,14 +14,22 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||||
|
github.com/cloudflare/cloudflare-go v0.91.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
github.com/distribution/reference v0.5.0 // indirect
|
github.com/distribution/reference v0.5.0 // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
|
||||||
github.com/go-logr/logr v1.4.1 // indirect
|
github.com/go-logr/logr v1.4.1 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
|
||||||
|
github.com/miekg/dns v1.1.58 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/term v0.5.0 // indirect
|
github.com/moby/term v0.5.0 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
|
@ -33,6 +42,7 @@ require (
|
||||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||||
|
golang.org/x/crypto v0.21.0 // indirect
|
||||||
golang.org/x/mod v0.16.0 // indirect
|
golang.org/x/mod v0.16.0 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
|
54
go.sum
54
go.sum
|
@ -1,9 +1,15 @@
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.86.0 h1:jEKN5VHNYNYtfDL2lUFLTRo+nOVNPFxpXTstVx0rqHI=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.86.0/go.mod h1:wYW/5UP02TUfBToa/yKbQHV+r6h1NnJ1Je7XjuGM4Jw=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.91.0 h1:L7IR+86qrZuEMSjGFg4cwRwtHqC8uCPmMUkP7BD4CPw=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.91.0/go.mod h1:nUqvBUUDRxNzsDSQjbqUNWHEIYAoUlgRmcAzMKlFdKs=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -19,25 +25,54 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
|
||||||
|
github.com/go-acme/lego/v4 v4.16.1/go.mod h1:AVvwdPned/IWpD/ihHhMsKnveF7HHYAz/CmtXi7OZoE=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
|
||||||
|
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||||
|
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
|
@ -48,16 +83,23 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
|
||||||
|
@ -79,8 +121,12 @@ go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7e
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||||
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -94,8 +140,10 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
|
@ -110,12 +158,15 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||||
|
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
|
||||||
|
@ -124,8 +175,9 @@ google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
|
||||||
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
228
src/go-proxy/autocert.go
Normal file
228
src/go-proxy/autocert.go
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
|
"github.com/go-acme/lego/v4/lego"
|
||||||
|
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||||
|
"github.com/go-acme/lego/v4/registration"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AutoCertConfig struct {
|
||||||
|
Email string
|
||||||
|
Domains []string `yaml:",flow"`
|
||||||
|
Provider string
|
||||||
|
Options map[string]string `yaml:",flow"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutoCertUser struct {
|
||||||
|
Email string
|
||||||
|
Registration *registration.Resource
|
||||||
|
key crypto.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *AutoCertUser) GetEmail() string {
|
||||||
|
return u.Email
|
||||||
|
}
|
||||||
|
func (u *AutoCertUser) GetRegistration() *registration.Resource {
|
||||||
|
return u.Registration
|
||||||
|
}
|
||||||
|
func (u *AutoCertUser) GetPrivateKey() crypto.PrivateKey {
|
||||||
|
return u.key
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutoCertProvider interface {
|
||||||
|
GetCert(*tls.ClientHelloInfo) (*tls.Certificate, error)
|
||||||
|
GetName() string
|
||||||
|
GetExpiry() time.Time
|
||||||
|
LoadCert() bool
|
||||||
|
ObtainCert() error
|
||||||
|
|
||||||
|
needRenew() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg AutoCertConfig) GetProvider() (AutoCertProvider, error) {
|
||||||
|
if len(cfg.Domains) == 0 {
|
||||||
|
return nil, fmt.Errorf("no domains specified")
|
||||||
|
}
|
||||||
|
if cfg.Provider == "" {
|
||||||
|
return nil, fmt.Errorf("no provider specified")
|
||||||
|
}
|
||||||
|
if cfg.Email == "" {
|
||||||
|
return nil, fmt.Errorf("no email specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to generate private key: %v", err)
|
||||||
|
}
|
||||||
|
user := &AutoCertUser{
|
||||||
|
Email: cfg.Email,
|
||||||
|
key: privKey,
|
||||||
|
}
|
||||||
|
legoCfg := lego.NewConfig(user)
|
||||||
|
legoCfg.Certificate.KeyType = certcrypto.RSA2048
|
||||||
|
legoClient, err := lego.NewClient(legoCfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create lego client: %v", err)
|
||||||
|
}
|
||||||
|
base := &AutoCertProviderBase{
|
||||||
|
name: cfg.Provider,
|
||||||
|
cfg: cfg,
|
||||||
|
user: user,
|
||||||
|
legoCfg: legoCfg,
|
||||||
|
client: legoClient,
|
||||||
|
}
|
||||||
|
switch cfg.Provider {
|
||||||
|
case "cloudflare":
|
||||||
|
return NewAutoCertCFProvider(base, cfg.Options)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unknown provider: %s", cfg.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutoCertProviderBase struct {
|
||||||
|
name string
|
||||||
|
cfg AutoCertConfig
|
||||||
|
user *AutoCertUser
|
||||||
|
legoCfg *lego.Config
|
||||||
|
client *lego.Client
|
||||||
|
|
||||||
|
tlsCert *tls.Certificate
|
||||||
|
expiry time.Time
|
||||||
|
mutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) GetCert(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
|
if p.tlsCert == nil {
|
||||||
|
aclog.Fatal("no certificate available")
|
||||||
|
}
|
||||||
|
if p.needRenew() {
|
||||||
|
p.mutex.Lock()
|
||||||
|
defer p.mutex.Unlock()
|
||||||
|
if p.needRenew() {
|
||||||
|
err := p.ObtainCert()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.tlsCert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) GetName() string {
|
||||||
|
return p.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) GetExpiry() time.Time {
|
||||||
|
return p.expiry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) ObtainCert() error {
|
||||||
|
client := p.client
|
||||||
|
if p.user.Registration == nil {
|
||||||
|
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.user.Registration = reg
|
||||||
|
}
|
||||||
|
req := certificate.ObtainRequest{
|
||||||
|
Domains: p.cfg.Domains,
|
||||||
|
Bundle: true,
|
||||||
|
}
|
||||||
|
cert, err := client.Certificate.Obtain(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = p.saveCert(cert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tlsCert, err := tls.X509KeyPair(cert.Certificate, cert.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.tlsCert = &tlsCert
|
||||||
|
x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[len(tlsCert.Certificate)-1])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.expiry = x509Cert.NotAfter
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) saveCert(cert *certificate.Resource) error {
|
||||||
|
err := os.WriteFile(keyFileDefault, cert.PrivateKey, 0600) // -rw-------
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.WriteFile(certFileDefault, cert.Certificate, 0644) // -rw-r--r--
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) needRenew() bool {
|
||||||
|
return p.expiry.Before(time.Now().Add(24 * time.Hour))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AutoCertProviderBase) LoadCert() bool {
|
||||||
|
cert, err := tls.LoadX509KeyPair(certFileDefault, keyFileDefault)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
x509Cert, err := x509.ParseCertificate(cert.Certificate[len(cert.Certificate)-1])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
p.tlsCert = &cert
|
||||||
|
p.expiry = x509Cert.NotAfter
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type AutoCertCFProvider struct {
|
||||||
|
*AutoCertProviderBase
|
||||||
|
*cloudflare.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAutoCertCFProvider(base *AutoCertProviderBase, opt map[string]string) (*AutoCertCFProvider, error) {
|
||||||
|
p := &AutoCertCFProvider{
|
||||||
|
base,
|
||||||
|
cloudflare.NewDefaultConfig(),
|
||||||
|
}
|
||||||
|
err := setOptions(p.Config, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
legoProvider, err := cloudflare.NewDNSProviderConfig(p.Config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create cloudflare provider: %v", err)
|
||||||
|
}
|
||||||
|
err = p.client.Challenge.SetDNS01Provider(legoProvider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to set challenge provider: %v", err)
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setOptions[T interface{}](cfg *T, opt map[string]string) error {
|
||||||
|
for k, v := range opt {
|
||||||
|
err := SetFieldFromSnake(cfg, k, v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import (
|
||||||
type Config interface {
|
type Config interface {
|
||||||
// Load() error
|
// Load() error
|
||||||
MustLoad()
|
MustLoad()
|
||||||
|
GetAutoCertProvider() (AutoCertProvider, error)
|
||||||
// MustReload()
|
// MustReload()
|
||||||
// Reload() error
|
// Reload() error
|
||||||
StartProviders()
|
StartProviders()
|
||||||
|
@ -64,6 +65,10 @@ func (cfg *config) MustLoad() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *config) GetAutoCertProvider() (AutoCertProvider, error) {
|
||||||
|
return cfg.AutoCert.GetProvider()
|
||||||
|
}
|
||||||
|
|
||||||
func (cfg *config) Reload() error {
|
func (cfg *config) Reload() error {
|
||||||
return cfg.Load()
|
return cfg.Load()
|
||||||
}
|
}
|
||||||
|
@ -97,6 +102,7 @@ func (cfg *config) StopWatching() {
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Providers map[string]*Provider `yaml:",flow"`
|
Providers map[string]*Provider `yaml:",flow"`
|
||||||
|
AutoCert AutoCertConfig `yaml:",flow"`
|
||||||
watcher Watcher
|
watcher Watcher
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,11 +63,6 @@ const (
|
||||||
ProviderKind_File = "file"
|
ProviderKind_File = "file"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
certPath = "certs/cert.crt"
|
|
||||||
keyPath = "certs/priv.key"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: default + per proxy
|
// TODO: default + per proxy
|
||||||
var (
|
var (
|
||||||
transport = &http.Transport{
|
transport = &http.Transport{
|
||||||
|
@ -92,11 +87,13 @@ const wildcardLabelPrefix = "proxy.*."
|
||||||
const clientUrlFromEnv = "FROM_ENV"
|
const clientUrlFromEnv = "FROM_ENV"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
configPath = "config.yml"
|
certFileDefault = "certs/cert.crt"
|
||||||
templatePath = "templates/panel.html"
|
keyFileDefault = "certs/priv.key"
|
||||||
|
configPath = "config.yml"
|
||||||
|
templatePath = "templates/panel.html"
|
||||||
)
|
)
|
||||||
|
|
||||||
const StreamStopListenTimeout = 2 * time.Second
|
const StreamStopListenTimeout = 1 * time.Second
|
||||||
|
|
||||||
const udpBufferSize = 1500
|
const udpBufferSize = 1500
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -17,12 +16,7 @@ import (
|
||||||
func (p *Provider) setConfigField(c *ProxyConfig, label string, value string, prefix string) error {
|
func (p *Provider) setConfigField(c *ProxyConfig, label string, value string, prefix string) error {
|
||||||
if strings.HasPrefix(label, prefix) {
|
if strings.HasPrefix(label, prefix) {
|
||||||
field := strings.TrimPrefix(label, prefix)
|
field := strings.TrimPrefix(label, prefix)
|
||||||
field = utils.snakeToCamel(field)
|
SetFieldFromSnake(c, field, value)
|
||||||
prop := reflect.ValueOf(c).Elem().FieldByName(field)
|
|
||||||
if prop.Kind() == 0 {
|
|
||||||
return fmt.Errorf("ignoring unknown field %s", field)
|
|
||||||
}
|
|
||||||
prop.Set(reflect.ValueOf(value))
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -172,7 +166,7 @@ func (p *Provider) getDockerProxyConfigs() ([]*ProxyConfig, error) {
|
||||||
|
|
||||||
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
|
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
containerSlice, err := dockerClient.ContainerList(ctx, container.ListOptions{All: true})
|
containerSlice, err := dockerClient.ContainerList(ctx, container.ListOptions{All: true})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to list containers: %v", err)
|
return nil, fmt.Errorf("unable to list containers: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ func isValidProxyPathMode(mode string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func redirectToTLS(w http.ResponseWriter, r *http.Request) {
|
func redirectToTLSHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
// Redirect to the same host but with HTTPS
|
// Redirect to the same host but with HTTPS
|
||||||
var redirectCode int
|
var redirectCode int
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
|
@ -155,7 +155,7 @@ func findHTTPRoute(host string, path string) (*HTTPRoute, error) {
|
||||||
return nil, fmt.Errorf("no matching route for subdomain %s", subdomain)
|
return nil, fmt.Errorf("no matching route for subdomain %s", subdomain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func httpProxyHandler(w http.ResponseWriter, r *http.Request) {
|
func proxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
route, err := findHTTPRoute(r.Host, r.URL.Path)
|
route, err := findHTTPRoute(r.Host, r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("request failed %s %s%s, error: %v",
|
err = fmt.Errorf("request failed %s %s%s, error: %v",
|
||||||
|
|
|
@ -8,3 +8,4 @@ var cfgl = logrus.WithField("component", "config")
|
||||||
var hrlog = logrus.WithField("component", "http_proxy")
|
var hrlog = logrus.WithField("component", "http_proxy")
|
||||||
var srlog = logrus.WithField("component", "stream")
|
var srlog = logrus.WithField("component", "stream")
|
||||||
var wlog = logrus.WithField("component", "watcher")
|
var wlog = logrus.WithField("component", "watcher")
|
||||||
|
var aclog = logrus.WithField("component", "autocert")
|
|
@ -7,66 +7,80 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
|
||||||
|
|
||||||
// flag.Parse()
|
// flag.Parse()
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
||||||
log.SetFormatter(&log.TextFormatter{
|
logrus.SetFormatter(&logrus.TextFormatter{
|
||||||
ForceColors: true,
|
ForceColors: true,
|
||||||
DisableColors: false,
|
DisableColors: false,
|
||||||
FullTimestamp: true,
|
FullTimestamp: true,
|
||||||
})
|
})
|
||||||
InitFSWatcher()
|
|
||||||
InitDockerWatcher()
|
|
||||||
|
|
||||||
cfg := NewConfig()
|
cfg := NewConfig()
|
||||||
cfg.MustLoad()
|
cfg.MustLoad()
|
||||||
|
|
||||||
|
autoCertProvider, err := cfg.GetAutoCertProvider()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
aclog.Warn(err)
|
||||||
|
autoCertProvider = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpProxyHandler http.Handler
|
||||||
|
var httpPanelHandler http.Handler
|
||||||
|
|
||||||
|
var proxyServer *Server
|
||||||
|
var panelServer *Server
|
||||||
|
|
||||||
|
if redirectHTTP {
|
||||||
|
httpProxyHandler = http.HandlerFunc(redirectToTLSHandler)
|
||||||
|
httpPanelHandler = http.HandlerFunc(redirectToTLSHandler)
|
||||||
|
} else {
|
||||||
|
httpProxyHandler = http.HandlerFunc(proxyHandler)
|
||||||
|
httpPanelHandler = http.HandlerFunc(panelHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
if autoCertProvider != nil {
|
||||||
|
ok := autoCertProvider.LoadCert()
|
||||||
|
if !ok {
|
||||||
|
err := autoCertProvider.ObtainCert()
|
||||||
|
if err != nil {
|
||||||
|
aclog.Fatal("error obtaining certificate ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aclog.Infof("certificate will be expired at %v and get renewed", autoCertProvider.GetExpiry())
|
||||||
|
|
||||||
|
}
|
||||||
|
proxyServer = NewServer(
|
||||||
|
"proxy",
|
||||||
|
autoCertProvider,
|
||||||
|
":80",
|
||||||
|
httpProxyHandler,
|
||||||
|
":443",
|
||||||
|
http.HandlerFunc(proxyHandler),
|
||||||
|
)
|
||||||
|
panelServer = NewServer(
|
||||||
|
"panel",
|
||||||
|
autoCertProvider,
|
||||||
|
":8080",
|
||||||
|
httpPanelHandler,
|
||||||
|
":8443",
|
||||||
|
http.HandlerFunc(panelHandler),
|
||||||
|
)
|
||||||
|
|
||||||
|
proxyServer.Start()
|
||||||
|
panelServer.Start()
|
||||||
|
|
||||||
|
InitFSWatcher()
|
||||||
|
InitDockerWatcher()
|
||||||
|
|
||||||
cfg.StartProviders()
|
cfg.StartProviders()
|
||||||
cfg.WatchChanges()
|
cfg.WatchChanges()
|
||||||
|
|
||||||
var certAvailable = utils.fileOK(certPath) && utils.fileOK(keyPath)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
log.Info("starting http server on port 80")
|
|
||||||
if certAvailable && redirectHTTP {
|
|
||||||
err = http.ListenAndServe(":80", http.HandlerFunc(redirectToTLS))
|
|
||||||
} else {
|
|
||||||
err = http.ListenAndServe(":80", http.HandlerFunc(httpProxyHandler))
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("http server error: ", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
log.Infof("starting http panel on port 8080")
|
|
||||||
err = http.ListenAndServe(":8080", http.HandlerFunc(panelHandler))
|
|
||||||
if err != nil {
|
|
||||||
log.Warning("http panel error: ", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if certAvailable {
|
|
||||||
go func() {
|
|
||||||
log.Info("starting https server on port 443")
|
|
||||||
err = http.ListenAndServeTLS(":443", certPath, keyPath, http.HandlerFunc(httpProxyHandler))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("https server error: ", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
log.Info("starting https panel on port 8443")
|
|
||||||
err := http.ListenAndServeTLS(":8443", certPath, keyPath, http.HandlerFunc(panelHandler))
|
|
||||||
if err != nil {
|
|
||||||
log.Warning("http panel error: ", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
sig := make(chan os.Signal, 1)
|
sig := make(chan os.Signal, 1)
|
||||||
signal.Notify(sig, syscall.SIGINT)
|
signal.Notify(sig, syscall.SIGINT)
|
||||||
signal.Notify(sig, syscall.SIGTERM)
|
signal.Notify(sig, syscall.SIGTERM)
|
||||||
|
@ -74,7 +88,9 @@ func main() {
|
||||||
|
|
||||||
<-sig
|
<-sig
|
||||||
cfg.StopWatching()
|
cfg.StopWatching()
|
||||||
cfg.StopProviders()
|
|
||||||
StopFSWatcher()
|
StopFSWatcher()
|
||||||
StopDockerWatcher()
|
StopDockerWatcher()
|
||||||
|
cfg.StopProviders()
|
||||||
|
panelServer.Stop()
|
||||||
|
proxyServer.Stop()
|
||||||
}
|
}
|
||||||
|
|
97
src/go-proxy/server.go
Normal file
97
src/go-proxy/server.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Name string
|
||||||
|
KeyFile string
|
||||||
|
CertFile string
|
||||||
|
CertProvider AutoCertProvider
|
||||||
|
http *http.Server
|
||||||
|
https *http.Server
|
||||||
|
httpStarted bool
|
||||||
|
httpsStarted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(name string, provider AutoCertProvider, httpAddr string, httpHandler http.Handler, httpsAddr string, httpsHandler http.Handler) *Server {
|
||||||
|
if provider != nil {
|
||||||
|
return &Server{
|
||||||
|
Name: name,
|
||||||
|
CertProvider: provider,
|
||||||
|
http: &http.Server{
|
||||||
|
Addr: httpAddr,
|
||||||
|
Handler: httpHandler,
|
||||||
|
},
|
||||||
|
https: &http.Server{
|
||||||
|
Addr: httpsAddr,
|
||||||
|
Handler: httpsHandler,
|
||||||
|
TLSConfig: &tls.Config{
|
||||||
|
GetCertificate: provider.GetCert,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Server{
|
||||||
|
Name: name,
|
||||||
|
KeyFile: keyFileDefault,
|
||||||
|
CertFile: certFileDefault,
|
||||||
|
http: &http.Server{
|
||||||
|
Addr: httpAddr,
|
||||||
|
Handler: httpHandler,
|
||||||
|
},
|
||||||
|
https: &http.Server{
|
||||||
|
Addr: httpsAddr,
|
||||||
|
Handler: httpsHandler,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() {
|
||||||
|
if s.http != nil {
|
||||||
|
s.httpStarted = true
|
||||||
|
logrus.Printf("starting http %s server on %s", s.Name, s.http.Addr)
|
||||||
|
go func() {
|
||||||
|
err := s.http.ListenAndServe()
|
||||||
|
s.handleErr("http", err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.https != nil && (s.CertProvider != nil || utils.fileOK(s.CertFile) && utils.fileOK(s.KeyFile)) {
|
||||||
|
s.httpsStarted = true
|
||||||
|
logrus.Printf("starting https %s server on %s", s.Name, s.https.Addr)
|
||||||
|
go func() {
|
||||||
|
err := s.https.ListenAndServeTLS(s.CertFile, s.KeyFile)
|
||||||
|
s.handleErr("https", err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Stop() {
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
|
||||||
|
if s.httpStarted {
|
||||||
|
errHTTP := s.http.Shutdown(ctx)
|
||||||
|
s.handleErr("http", errHTTP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.httpsStarted {
|
||||||
|
errHTTPS := s.https.Shutdown(ctx)
|
||||||
|
s.handleErr("https", errHTTPS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleErr(scheme string, err error) {
|
||||||
|
switch err {
|
||||||
|
case nil, http.ErrServerClosed:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
logrus.Fatalf("failed to start %s %s server: %v", scheme, s.Name, err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -91,7 +92,7 @@ func (*Utils) healthCheckStream(scheme, host string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Utils) snakeToCamel(s string) string {
|
func (*Utils) snakeToPascal(s string) string {
|
||||||
toHyphenCamel := http.CanonicalHeaderKey(strings.ReplaceAll(s, "_", "-"))
|
toHyphenCamel := http.CanonicalHeaderKey(strings.ReplaceAll(s, "_", "-"))
|
||||||
return strings.ReplaceAll(toHyphenCamel, "-", "")
|
return strings.ReplaceAll(toHyphenCamel, "-", "")
|
||||||
}
|
}
|
||||||
|
@ -192,3 +193,13 @@ func (*Utils) fileOK(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetFieldFromSnake[T interface{}, VT interface{}](obj *T, field string, value VT) error {
|
||||||
|
field = utils.snakeToPascal(field)
|
||||||
|
prop := reflect.ValueOf(obj).Elem().FieldByName(field)
|
||||||
|
if prop.Kind() == 0 {
|
||||||
|
return fmt.Errorf("unknown field %s", field)
|
||||||
|
}
|
||||||
|
prop.Set(reflect.ValueOf(value))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue