Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .examples/docker-compose-oidc/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
services:
dex:
network_mode: host
image: ghcr.io/dexidp/dex:latest
command: ["dex", "serve", "/etc/dex/config.yaml"]
configs:
- source: dex_config_yaml
target: /etc/dex/config.yaml
healthcheck:
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5556/healthz"]
interval: 1s
timeout: 1s
retries: 5
start_period: 1s

gatus:
network_mode: host
image: twinproduction/gatus:latest
volumes:
- ../../config.yml:/config/02_config.yaml
environment:
- GATUS_CONFIG_PATH=/config
configs:
- source: gatus_config_ext
target: /config/01_config.yaml
depends_on:
dex:
condition: service_healthy

configs:
dex_config_yaml:
content: |
issuer: http://localhost:5556/
storage:
type: sqlite3
config:
file: /var/dex/dex.db
web:
http: 0.0.0.0:5556
enablePasswordDB: true
staticClients:
- id: gatus
name: 'Gatus'
secret: gatus-client-secret
redirectURIs:
- 'http://localhost:8080/authorization-code/callback'
staticPasswords:
- email: "[email protected]"
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"

gatus_config_ext:
content: |
security:
oidc:
issuer-url: "http://localhost:5556/"
redirect-url: "http://localhost:8080/authorization-code/callback"
client-id: "gatus"
client-secret: "gatus-client-secret"
scopes:
- openid

89 changes: 89 additions & 0 deletions .examples/docker-compose-reverse-proxy-oicd/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

services:
dex:
network_mode: host
image: ghcr.io/dexidp/dex:latest
command: ["dex", "serve", "/etc/dex/config.yaml"]
configs:
- source: dex_config_yaml
target: /etc/dex/config.yaml
healthcheck:
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5556/healthz"]
interval: 10s
timeout: 5s
retries: 5
start_period: 1s

caddy:
network_mode: host
image: caddy:latest
container_name: gatus_proxy
configs:
- source: caddyfile
target: /etc/caddy/Caddyfile

gatus:
network_mode: host
image: twinproduction/gatus:latest
container_name: gatus_behind_proxy
volumes:
- ../../config.yml:/config/02_config.yaml
environment:
- GATUS_CONFIG_PATH=/config
configs:
- source: gatus_config_ext
target: /config/01_config.yaml
depends_on:
dex:
condition: service_healthy


configs:
dex_config_yaml:
content: |
issuer: http://localhost:5556/
storage:
type: sqlite3
config:
file: /var/dex/dex.db
web:
http: 0.0.0.0:5556
enablePasswordDB: true
staticClients:
- id: gatus
name: 'Gatus'
secret: gatus-client-secret
redirectURIs:
- 'http://localhost:8080/gatus/authorization-code/callback'
staticPasswords:
- email: "[email protected]"
# bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W"
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"

gatus_config_ext:
content: |
web:
base-path: /gatus/
port: 8081
security:
oidc:
issuer-url: "http://localhost:5556/"
redirect-url: "http://localhost:8080/gatus/authorization-code/callback"
client-id: "gatus"
client-secret: "gatus-client-secret"
scopes:
- openid
caddyfile:
content: |
{
auto_https off
http_port 8080
}

http://localhost:8080 {
handle_path /gatus/* {
reverse_proxy http://localhost:8081
}
}
46 changes: 46 additions & 0 deletions .examples/docker-compose-reverse-proxy/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
networks:
caddy_network:
name: gatus_proxy_network

services:
caddy:
networks:
- caddy_network
image: caddy:latest
container_name: gatus_proxy
ports:
- 8080:8080
configs:
- source: caddyfile
target: /etc/caddy/Caddyfile
gatus:
networks:
- caddy_network
image: twinproduction/gatus:latest
container_name: gatus_behind_proxy

volumes:
- ../../config.yml:/config/02_config.yaml
environment:
- GATUS_CONFIG_PATH=/config
configs:
- source: gatus_config_ext
target: /config/01_config.yaml

configs:
gatus_config_ext:
content: |
ui:
base: /gatus/
caddyfile:
content: |
{
auto_https off
http_port 8080
}

http://localhost:8080 {
handle_path /gatus/* {
reverse_proxy http://gatus_behind_proxy:8080
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ If you want to test it locally, see [Docker](#docker).
| `web` | Web configuration. | `{}` |
| `web.address` | Address to listen on. | `0.0.0.0` |
| `web.port` | Port to listen on. | `8080` |
| `web.base-path` | `href` attribute of the HTML `<base>` tag. Use this if you want to host Gatus on a subpath (e.g. `/status/`). Has to end with '/'. | `/` |
| `web.read-buffer-size` | Buffer size for reading requests from a connection. Also limit for the maximum header size. | `8192` |
| `web.tls.certificate-file` | Optional public certificate file for TLS in PEM format. | `""` |
| `web.tls.private-key-file` | Optional private key file for TLS in PEM format. | `""` |
Expand Down
2 changes: 1 addition & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func New(cfg *config.Config) *API {
}
if cfg.UI == nil {
logr.Warnf("[api.New] nil ui config passed as parameter. This should only happen in tests. Using default ui configuration")
cfg.UI = ui.GetDefaultConfig()
cfg.UI = ui.GetDefaultConfig("/")
}
api.router = api.createRouter(cfg)
return api
Expand Down
12 changes: 6 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,13 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) {
}
// XXX: End of v6.0.0 removals
ValidateAlertingConfig(config.Alerting, config.Endpoints, config.ExternalEndpoints)
if err := ValidateSecurityConfig(config); err != nil {
if err := ValidateWebConfig(config); err != nil {
return nil, err
}
if err := ValidateEndpointsConfig(config); err != nil {
if err := ValidateSecurityConfig(config); err != nil {
return nil, err
}
if err := ValidateWebConfig(config); err != nil {
if err := ValidateEndpointsConfig(config); err != nil {
return nil, err
}
if err := ValidateUIConfig(config); err != nil {
Expand Down Expand Up @@ -452,9 +452,9 @@ func ValidateMaintenanceConfig(config *Config) error {

func ValidateUIConfig(config *Config) error {
if config.UI == nil {
config.UI = ui.GetDefaultConfig()
config.UI = ui.GetDefaultConfig(config.Web.BasePath)
} else {
if err := config.UI.ValidateAndSetDefaults(); err != nil {
if err := config.UI.ValidateAndSetDefaults(config.Web.BasePath); err != nil {
return err
}
}
Expand Down Expand Up @@ -575,7 +575,7 @@ func ValidateUniqueKeys(config *Config) error {

func ValidateSecurityConfig(config *Config) error {
if config.Security != nil {
if !config.Security.ValidateAndSetDefaults() {
if !config.Security.ValidateAndSetDefaults(config.Web.BasePath) {
logr.Debug("[config.ValidateSecurityConfig] Basic security configuration has been validated")
return ErrInvalidSecurityConfig
}
Expand Down
2 changes: 1 addition & 1 deletion config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1803,7 +1803,7 @@ endpoints:
if config.Security == nil {
t.Fatal("config.Security shouldn't have been nil")
}
if !config.Security.ValidateAndSetDefaults() {
if !config.Security.ValidateAndSetDefaults("/") {
t.Error("Security config should've been valid")
}
if config.Security.Basic == nil {
Expand Down
10 changes: 8 additions & 2 deletions config/ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Config struct {
// Non-configurable - used for UI rendering //
//////////////////////////////////////////////
MaximumNumberOfResults int `yaml:"-"` // MaximumNumberOfResults to display on the page, it's not configurable because we're passing it from the storage config
BasePath string `yaml:"-"` // basePath is from Web.BasePath
}

func (cfg *Config) IsDarkMode() bool {
Expand All @@ -72,7 +73,7 @@ func (btn *Button) Validate() error {
}

// GetDefaultConfig returns a Config struct with the default values
func GetDefaultConfig() *Config {
func GetDefaultConfig(basePath string) *Config {
return &Config{
Title: defaultTitle,
Description: defaultDescription,
Expand All @@ -86,11 +87,12 @@ func GetDefaultConfig() *Config {
DefaultSortBy: defaultSortBy,
DefaultFilterBy: defaultFilterBy,
MaximumNumberOfResults: storage.DefaultMaximumNumberOfResults,
BasePath: basePath,
}
}

// ValidateAndSetDefaults validates the UI configuration and sets the default values if necessary.
func (cfg *Config) ValidateAndSetDefaults() error {
func (cfg *Config) ValidateAndSetDefaults(basePath string) error {
if len(cfg.Title) == 0 {
cfg.Title = defaultTitle
}
Expand Down Expand Up @@ -133,6 +135,10 @@ func (cfg *Config) ValidateAndSetDefaults() error {
return err
}
}
cfg.BasePath = basePath
if len(cfg.BasePath) == 0 {
return errors.New("basePath cannot be empty")
}
// Validate that the template works
t, err := template.ParseFS(static.FileSystem, static.IndexPath)
if err != nil {
Expand Down
10 changes: 5 additions & 5 deletions config/ui/ui_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
Logo: "",
Link: "",
}
if err := cfg.ValidateAndSetDefaults(); err != nil {
if err := cfg.ValidateAndSetDefaults("/"); err != nil {
t.Error("expected no error, got", err.Error())
}
if cfg.Title != defaultTitle {
Expand Down Expand Up @@ -54,7 +54,7 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
DefaultSortBy: "health",
DefaultFilterBy: "failing",
}
if err := cfg.ValidateAndSetDefaults(); err != nil {
if err := cfg.ValidateAndSetDefaults("/"); err != nil {
t.Error("expected no error, got", err.Error())
}
if cfg.Title != "Custom Title" {
Expand Down Expand Up @@ -92,7 +92,7 @@ func TestConfig_ValidateAndSetDefaults(t *testing.T) {
Header: "",
DashboardSubheading: "",
}
if err := cfg.ValidateAndSetDefaults(); err != nil {
if err := cfg.ValidateAndSetDefaults("/"); err != nil {
t.Error("expected no error, got", err.Error())
}
if cfg.Title != "Custom Title" {
Expand Down Expand Up @@ -215,7 +215,7 @@ func TestConfig_ValidateAndSetDefaults_DefaultSortBy(t *testing.T) {
for _, scenario := range scenarios {
t.Run(scenario.Name, func(t *testing.T) {
cfg := &Config{DefaultSortBy: scenario.DefaultSortBy}
err := cfg.ValidateAndSetDefaults()
err := cfg.ValidateAndSetDefaults("/")
if !errors.Is(err, scenario.ExpectedError) {
t.Errorf("expected error %v, got %v", scenario.ExpectedError, err)
}
Expand Down Expand Up @@ -267,7 +267,7 @@ func TestConfig_ValidateAndSetDefaults_DefaultFilterBy(t *testing.T) {
for _, scenario := range scenarios {
t.Run(scenario.Name, func(t *testing.T) {
cfg := &Config{DefaultFilterBy: scenario.DefaultFilterBy}
err := cfg.ValidateAndSetDefaults()
err := cfg.ValidateAndSetDefaults("/")
if !errors.Is(err, scenario.ExpectedError) {
t.Errorf("expected error %v, got %v", scenario.ExpectedError, err)
}
Expand Down
Loading