docs: improve Caddyfile header and note about misconfigured caddy service, minor docs update

This commit is contained in:
Pasha Sviderski
2025-12-22 16:31:15 +10:00
parent 65e9cdd444
commit 2345ee9856
6 changed files with 50 additions and 24 deletions
+8 -3
View File
@@ -12,14 +12,16 @@ import (
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
"time"
"github.com/psviderski/uncloud/internal/machine/store" "github.com/psviderski/uncloud/internal/machine/store"
"github.com/psviderski/uncloud/pkg/api" "github.com/psviderski/uncloud/pkg/api"
) )
const ( const (
caddyfileHeader = `# This file is autogenerated by Uncloud based on the configuration of running services. caddyfileHeaderFmt = `# Caddyfile autogenerated by Uncloud (DO NOT EDIT): %s
# Do not edit manually. Any manual changes will be overwritten on the next update. # Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
` `
caddyfileTemplate = `# Health check endpoint to verify Caddy reachability on this machine. caddyfileTemplate = `# Health check endpoint to verify Caddy reachability on this machine.
http:// { http:// {
@@ -56,7 +58,9 @@ https://{{$hostname}} {
}{{end}} }{{end}}
` `
caddyfileUnavailabeFooter = `# NOTE: User-defined configs for services were skipped because Caddy is not running on this machine caddyfileUnavailabeFooter = `# NOTE: User-defined configs for services were skipped because Caddy is not running on this machine
# or the latest generated config is invalid. Please check the Caddy logs if it's running. # (not accessible via the shared admin socket /run/uncloud/caddy/admin.sock) or the latest
# generated config is invalid. Please check the service 'caddy' is running (uc inspect caddy)
# and its logs for more details (uc logs caddy).
` `
) )
@@ -120,6 +124,7 @@ func (g *CaddyfileGenerator) Generate(
return "", fmt.Errorf("generate base Caddyfile from service ports: %w", err) return "", fmt.Errorf("generate base Caddyfile from service ports: %w", err)
} }
caddyfileHeader := fmt.Sprintf(caddyfileHeaderFmt, time.Now().UTC().Format(time.RFC3339))
if !includeCustom { if !includeCustom {
return fmt.Sprintf("%s\n%s\n%s", caddyfileHeader, caddyfile, caddyfileUnavailabeFooter), nil return fmt.Sprintf("%s\n%s\n%s", caddyfileHeader, caddyfile, caddyfileUnavailabeFooter), nil
} }
+30 -13
View File
@@ -3,6 +3,7 @@ package caddyconfig
import ( import (
"context" "context"
"errors" "errors"
"regexp"
"strings" "strings"
"testing" "testing"
"time" "time"
@@ -17,8 +18,17 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const testCaddyfileHeader = `# This file is autogenerated by Uncloud based on the configuration of running services. // generatedTimestampRegex matches the "(DO NOT EDIT): <RFC3339 timestamp>" part of the header.
# Do not edit manually. Any manual changes will be overwritten on the next update. var generatedTimestampRegex = regexp.MustCompile(`\(DO NOT EDIT\): \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)
// normaliseGeneratedTimestamp replaces dynamic timestamps with a placeholder for test comparison.
func normaliseGeneratedTimestamp(caddyfile string) string {
return generatedTimestampRegex.ReplaceAllString(caddyfile, "(DO NOT EDIT): TIMESTAMP_PLACEHOLDER")
}
const testCaddyfileHeader = `# Caddyfile autogenerated by Uncloud (DO NOT EDIT): TIMESTAMP_PLACEHOLDER
# Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
# Health check endpoint to verify Caddy reachability on this machine. # Health check endpoint to verify Caddy reachability on this machine.
http:// { http:// {
@@ -190,7 +200,7 @@ https://secure.example.com {
} }
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, tt.want, config, "Generated Caddyfile doesn't match") assert.Equal(t, tt.want, normaliseGeneratedTimestamp(config), "Generated Caddyfile doesn't match")
}) })
} }
} }
@@ -216,8 +226,9 @@ func TestCaddyfileGeneratorWithCustomConfigs(t *testing.T) {
time.Now(), time.Now(),
), ),
}, },
want: `# This file is autogenerated by Uncloud based on the configuration of running services. want: `# Caddyfile autogenerated by Uncloud (DO NOT EDIT): TIMESTAMP_PLACEHOLDER
# Do not edit manually. Any manual changes will be overwritten on the next update. # Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
# User-defined global config from service 'caddy'. # User-defined global config from service 'caddy'.
# Global Caddy configuration # Global Caddy configuration
@@ -412,8 +423,9 @@ web.example.com {
time.Now(), time.Now(),
), ),
}, },
want: `# This file is autogenerated by Uncloud based on the configuration of running services. want: `# Caddyfile autogenerated by Uncloud (DO NOT EDIT): TIMESTAMP_PLACEHOLDER
# Do not edit manually. Any manual changes will be overwritten on the next update. # Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
# User-defined global config from service 'caddy'. # User-defined global config from service 'caddy'.
# Global config # Global config
@@ -649,8 +661,9 @@ badconfig.com {
time.Now(), time.Now(),
), ),
}, },
want: `# This file is autogenerated by Uncloud based on the configuration of running services. want: `# Caddyfile autogenerated by Uncloud (DO NOT EDIT): TIMESTAMP_PLACEHOLDER
# Do not edit manually. Any manual changes will be overwritten on the next update. # Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
# User-defined global config from service 'caddy'. # User-defined global config from service 'caddy'.
# Global config from test machine # Global config from test machine
@@ -831,7 +844,7 @@ valid.example.com {
} }
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, tt.want, config, "Generated Caddyfile doesn't match") assert.Equal(t, tt.want, normaliseGeneratedTimestamp(config), "Generated Caddyfile doesn't match")
}) })
} }
} }
@@ -926,7 +939,9 @@ http://api.example.com {
} }
# NOTE: User-defined configs for services were skipped because Caddy is not running on this machine # NOTE: User-defined configs for services were skipped because Caddy is not running on this machine
# or the latest generated config is invalid. Please check the Caddy logs if it's running. # (not accessible via the shared admin socket /run/uncloud/caddy/admin.sock) or the latest
# generated config is invalid. Please check the service 'caddy' is running (uc inspect caddy)
# and its logs for more details (uc logs caddy).
`, `,
}, },
{ {
@@ -950,7 +965,9 @@ http://api.example.com {
} }
# NOTE: User-defined configs for services were skipped because Caddy is not running on this machine # NOTE: User-defined configs for services were skipped because Caddy is not running on this machine
# or the latest generated config is invalid. Please check the Caddy logs if it's running. # (not accessible via the shared admin socket /run/uncloud/caddy/admin.sock) or the latest
# generated config is invalid. Please check the service 'caddy' is running (uc inspect caddy)
# and its logs for more details (uc logs caddy).
`, `,
}, },
} }
@@ -964,7 +981,7 @@ http://api.example.com {
config, err := generator.Generate(ctx, tt.containers, false) config, err := generator.Generate(ctx, tt.containers, false)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, tt.want, config, "Generated Caddyfile doesn't match") assert.Equal(t, tt.want, normaliseGeneratedTimestamp(config), "Generated Caddyfile doesn't match")
}) })
} }
} }
+2 -2
View File
@@ -293,7 +293,7 @@ func TestDeployment(t *testing.T) {
config, err := cli.Caddy.GetConfig(ctx, nil) config, err := cli.Caddy.GetConfig(ctx, nil)
require.NoError(t, err) require.NoError(t, err)
assert.Contains(t, config.Caddyfile, "# This file is autogenerated by Uncloud") assert.Contains(t, config.Caddyfile, "# Caddyfile autogenerated by Uncloud")
assert.Contains(t, config.Caddyfile, "handle /.uncloud-verify") assert.Contains(t, config.Caddyfile, "handle /.uncloud-verify")
}) })
@@ -423,7 +423,7 @@ myapp.example.com {
}, 5*time.Second, 100*time.Millisecond, }, 5*time.Second, 100*time.Millisecond,
"Expected both custom configs to be included in the Caddyfile") "Expected both custom configs to be included in the Caddyfile")
assert.Contains(t, config.Caddyfile, "# This file is autogenerated by Uncloud") assert.Contains(t, config.Caddyfile, "# Caddyfile autogenerated by Uncloud")
assert.Contains(t, config.Caddyfile, "handle /.uncloud-verify") assert.Contains(t, config.Caddyfile, "handle /.uncloud-verify")
assert.Contains(t, config.Caddyfile, caddyCaddyfile, assert.Contains(t, config.Caddyfile, caddyCaddyfile,
"Expected user-defined global Caddy config to be included in the Caddyfile") "Expected user-defined global Caddy config to be included in the Caddyfile")
@@ -10,7 +10,7 @@ with [Let's Encrypt](https://letsencrypt.org/), and route requests to your servi
## How it works ## How it works
By default, Caddy runs as a global service `caddy` on every machine in your cluster, listening on the host ports 80 By default, Caddy runs as a global service `caddy` on every machine in your cluster, listening on the host ports 80
(HTTP) and 443 (HTTPS). (HTTP), 443 (HTTPS), and 443/UDP (HTTP/3).
It's deployed during cluster initialisation (`uc machine init`) unless you use the `--no-caddy` flag. It's deployed during cluster initialisation (`uc machine init`) unless you use the `--no-caddy` flag.
See [Managing Caddy](3-managing-caddy.md) for deployment and customisation instructions. See [Managing Caddy](3-managing-caddy.md) for deployment and customisation instructions.
@@ -197,8 +197,9 @@ debugging and verifying your `x-caddy` configs.
Example output: Example output:
```caddyfile ```caddyfile
# This file is autogenerated by Uncloud based on the configuration of running services. # Caddyfile autogenerated by Uncloud (DO NOT EDIT): 2025-12-20T22:43:56Z
# Do not edit manually. Any manual changes will be overwritten on the next update. # Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
# User-defined global config from service 'caddy'. # User-defined global config from service 'caddy'.
*.example.com { *.example.com {
@@ -94,6 +94,7 @@ services:
x-ports: x-ports:
- 80:80@host - 80:80@host
- 443:443@host - 443:443@host
- 443:443/udp@host
x-caddy: Caddyfile x-caddy: Caddyfile
deploy: deploy:
mode: global mode: global
@@ -138,7 +139,8 @@ internal.example.com {
:::info note :::info note
The specified `command`, `environment`, `volumes`, and `x-ports` properties are essential for Caddy to function The specified `command`, `environment`, `volumes`, and `x-ports` properties are essential for Caddy to function
correctly in the Uncloud cluster. correctly in the Uncloud cluster. Do not change the source paths of the volume mounts as the Uncloud daemon relies on
them to communicate with Caddy and update its configuration.
::: :::
@@ -160,8 +162,9 @@ uc caddy config
Example output: Example output:
```caddyfile ```caddyfile
# This file is autogenerated by Uncloud based on the configuration of running services. # Caddyfile autogenerated by Uncloud (DO NOT EDIT): 2025-12-22T10:30:12Z
# Do not edit manually. Any manual changes will be overwritten on the next update. # Automatically updated on service or health status changes.
# Docs: https://uncloud.run/docs/concepts/ingress/overview
# User-defined global config from service 'caddy'. # User-defined global config from service 'caddy'.
# Global options. # Global options.