mirror of
https://github.com/wweir/sower.git
synced 2026-10-20 00:15:34 +00:00
fix: fallback to system cache for sowerd service
This commit is contained in:
@@ -92,6 +92,7 @@
|
||||
- Upstream TLS behavior is configured only on the client side; `sowerd` remains a normal TLS server and does not need uTLS-specific logic.
|
||||
- Rule loading supports local files and remote gzip-compressed HTTP sources.
|
||||
- Fake site directory mode is loopback-only on port `80` to avoid exposing local static assets directly to the public internet.
|
||||
- `sowerd` prefers the user cache directory for ACME state, but falls back to `/var/cache/sower` so systemd services can start without `HOME`/`XDG_CACHE_HOME` or a config file.
|
||||
|
||||
## Operational Notes
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ On the server-side, sowerd runs just like a web server proxy. It will bind two p
|
||||
|
||||
`sowerd` validates its configuration at startup, redacts secrets from logs, and exits immediately if `80` / `443` listeners cannot be established.
|
||||
|
||||
When `sowerd` runs as a system service without `HOME` or `XDG_CACHE_HOME`, it falls back to `/var/cache/sower` for certificate cache state so environment-only startup still works without a config file.
|
||||
|
||||
You can use your own certificate or the certificate automatically applied for by sowerd from [`Let's Encrypt`](https://letsencrypt.org/).
|
||||
|
||||
When `fake_site` points to a local directory, `sowerd` serves that directory only through loopback fallback traffic on `127.0.0.1:80`, while public HTTP traffic is still redirected to HTTPS.
|
||||
|
||||
+15
-6
@@ -33,6 +33,7 @@ import (
|
||||
const (
|
||||
httpShutdownTimeout = 5 * time.Second
|
||||
probeTimeout = 10 * time.Second
|
||||
systemCacheDir = "/var/cache/sower"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -174,18 +175,26 @@ func run(ctx context.Context, conf config.SowerdConfig) error {
|
||||
}
|
||||
|
||||
func cacheDir() (string, error) {
|
||||
base, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get user cache dir: %w", err)
|
||||
dir, fallbackErr := resolveCacheDir(os.UserCacheDir, systemCacheDir)
|
||||
if fallbackErr != nil {
|
||||
slog.Warn("user cache dir unavailable, fallback to system cache dir",
|
||||
"error", fallbackErr,
|
||||
"dir", dir)
|
||||
}
|
||||
|
||||
dir := filepath.Join(base, "sower")
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
return "", fmt.Errorf("create cache dir: %w", err)
|
||||
return "", fmt.Errorf("create cache dir %s: %w", dir, err)
|
||||
}
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func resolveCacheDir(userCacheDir func() (string, error), fallbackDir string) (string, error) {
|
||||
base, err := userCacheDir()
|
||||
if err != nil {
|
||||
return fallbackDir, err
|
||||
}
|
||||
return filepath.Join(base, "sower"), nil
|
||||
}
|
||||
|
||||
func buildTLSConfig(cacheDir string, cfg config.SowerdConfig) (*autocert.Manager, *tls.Config, error) {
|
||||
certManager := &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/sower-proxy/sower/config"
|
||||
@@ -76,3 +78,51 @@ func TestHasInstallFlag(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveCacheDir(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
userCache func() (string, error)
|
||||
fallbackDir string
|
||||
wantDir string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "user cache dir available",
|
||||
userCache: func() (string, error) {
|
||||
return "/tmp/cache", nil
|
||||
},
|
||||
fallbackDir: "/var/cache/sower",
|
||||
wantDir: filepath.Join("/tmp/cache", "sower"),
|
||||
},
|
||||
{
|
||||
name: "fallback to system cache dir",
|
||||
userCache: func() (string, error) {
|
||||
return "", errors.New("missing home")
|
||||
},
|
||||
fallbackDir: "/var/cache/sower",
|
||||
wantDir: "/var/cache/sower",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
gotDir, err := resolveCacheDir(tt.userCache, tt.fallbackDir)
|
||||
if tt.wantErr && err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if !tt.wantErr && err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if gotDir != tt.wantDir {
|
||||
t.Fatalf("resolveCacheDir() = %q, want %q", gotDir, tt.wantDir)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user