Skip to content
This repository was archived by the owner on Aug 3, 2024. It is now read-only.

Commit

Permalink
deploy: Add traefik configuration (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
amalshaji authored Mar 3, 2023
1 parent 715f9d5 commit 15eca3a
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 2 deletions.
2 changes: 1 addition & 1 deletion cmd/beaver_client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func startTunnels(tunnels []client.TunnelConfig) {
for _, proxyTunnel := range tunnels {
config, err := client.LoadConfiguration(configFile, proxyTunnel.Subdomain, proxyTunnel.Port, showWsReadErrors)
if err != nil {
log.Fatalf("Unable to load configuration : %s", err)
log.Fatalf("Unable to load configuration: %s", err)
}
proxy := client.NewClient(&config)
proxies = append(proxies, proxy)
Expand Down
6 changes: 6 additions & 0 deletions deployments/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
ACME_EMAIL=
TUNNEL_DOMAIN=
DNS_PROVIDER=

# DNS specific
CLOUDFLARE_DNS_API_TOKEN=
42 changes: 42 additions & 0 deletions deployments/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
services:
beaver:
image: amalshaji/beaver:main
volumes:
- ./beaver_server.yaml:/app/config/beaver_server.yaml
- ./data:/app/data/
expose:
- 8080
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.http.routers.beaver.tls=true
- traefik.http.routers.beaver.tls.certresolver=letsencrypt
- traefik.http.routers.beaver.rule=HostRegexp(`${TUNNEL_DOMAIN}`, `{subdomain:[a-z0-9-]+}.${TUNNEL_DOMAIN}`)
- traefik.http.routers.beaver.tls.domains[0].main=${TUNNEL_DOMAIN}
- traefik.http.routers.beaver.tls.domains[0].sans=*.${TUNNEL_DOMAIN}
traefik:
image: traefik:v2.9.8
env_file:
- .env
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik-public-certificates:/certificates
labels:
- traefik.enable=true
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --log.level=DEBUG
- --accesslog
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --certificatesresolvers.letsencrypt.acme.dnschallenge=true
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}
- --certificatesresolvers.letsencrypt.acme.storage=/certificates/acme.json
- --certificatesresolvers.letsencrypt.acme.dnschallenge.provider=${DNS_PROVIDER}
- --certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=0
10 changes: 10 additions & 0 deletions internal/client/config.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package client

import (
"fmt"
"os"
"strings"

"github.com/amalshaji/beaver/internal/utils"
gonanoid "github.com/matoous/go-nanoid/v2"
uuid "github.com/nu7hatch/gouuid"

Expand Down Expand Up @@ -44,9 +46,11 @@ func (config *Config) setDefaults() {
if config.Target == "" {
config.Target = "wss://x.amal.sh"
}

if config.PoolIdleSize == 0 {
config.PoolIdleSize = 1
}

if config.PoolMaxSize == 0 {
config.PoolMaxSize = 100
}
Expand Down Expand Up @@ -78,7 +82,13 @@ func LoadConfiguration(configFile string, subdomain string, port int, showWsRead
if err != nil {
panic(err)
}
} else {
err = utils.ValidateSubdomain(subdomain)
if err != nil {
return Config{}, fmt.Errorf("invalid subdomain: '%s'; %s", subdomain, err.Error())
}
}

config.subdomain = subdomain
config.port = port
config.showWsReadErrors = showWsReadErrors
Expand Down
4 changes: 4 additions & 0 deletions internal/server/handlers/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ func register(c echo.Context) error {
app := c.Get("app").(*app.App)

subdomain := c.Request().Header.Get("X-TUNNEL-SUBDOMAIN")
if err := utils.ValidateSubdomain(subdomain); err != nil {
return utils.ProxyErrorf(c, "invalid subdomain: '%s'; %s", subdomain, utils.ErrInvalidSubdomain.Error())
}

localServer := c.Request().Header.Get("X-LOCAL-SERVER")

secretKey := c.Request().Header.Get("X-SECRET-KEY")
Expand Down
17 changes: 16 additions & 1 deletion internal/utils/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package utils
import (
"errors"
"net/mail"
"regexp"
"strings"
)

var ErrPasswordNotLongEnough = errors.New("password must be atleast 6 chars long")
var (
ErrPasswordNotLongEnough = errors.New("password must be atleast 6 chars long")
ErrInvalidSubdomain = errors.New("subdomain must contain only a-z, 0-9 and `-`(not leading or trailing)")
)

// Remove any leading or trailing whitespace
func SanitizeString(value string) string {
Expand All @@ -24,3 +28,14 @@ func ValidatePassword(input string) error {
}
return nil
}

func ValidateSubdomain(subdomain string) error {
matched, err := regexp.Match(`^([a-z0-9]+([-][a-z0-9]+)*)$`, []byte(subdomain))
if err != nil {
return err
}
if !matched {
return ErrInvalidSubdomain
}
return nil
}
17 changes: 17 additions & 0 deletions internal/utils/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,20 @@ func TestValidatePassword(t *testing.T) {
assert.ErrorIs(t, ValidatePassword(tc.input), tc.want)
}
}

func TestValidateSubdomain(t *testing.T) {
tests := []struct {
input string
want error
}{
{input: "beaver-test-dev", want: nil},
{input: "beaver.test", want: ErrInvalidSubdomain},
{input: "-beaver", want: ErrInvalidSubdomain},
{input: "beaver-", want: ErrInvalidSubdomain},
{input: "beaver_test", want: ErrInvalidSubdomain},
}

for _, tc := range tests {
assert.ErrorIs(t, ValidateSubdomain(tc.input), tc.want)
}
}

0 comments on commit 15eca3a

Please sign in to comment.