From 9fedbac5611b8de7e9d83850dd755b36646d9db6 Mon Sep 17 00:00:00 2001 From: Peter Downs Date: Mon, 17 Jul 2023 12:28:17 -0400 Subject: [PATCH] bugfix: switch to unix socket for embedded caddy adminapi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug first reported by Albert Gimeno here: https://twitter.com/gimenete/status/1680966368626192389?s=20 > For my regular job I realized we are using caddy as well internally > and I can't have both projects running at the same time. localias says > that the localias daemon is already running but it's actually the > embedded caddy in another app. I was able to reproduce this problem: 1. `localias daemon start` — binds localhost:2019 to localias's embedded caddy admin server 2. `caddy start` — binds localhost:2019 to the caddy admin server 3. `localias daemon stop` or `localias daemon reload` — requests are handled by caddy, not localias's embedded caddy. This breaks localias's expected behavior and interferes with the other caddy server, Not Good. This PR fixes the problem by using a unix domain socket to communicate with the embedded caddy server. This socket is stored in the localias state directory, just like the rest of the server's config data. As reported in https://github.com/caddyserver/caddy/issues/2749 this is well-supported by Caddy, which made implementing this very easy — just needed to switch `admin localhost:2019` to `admin "unix//absolute/path/to/socket"`. The fix uncovered a minor problem in the way I was determining the Caddy server API address but that was easily fixed by reading the Caddy docs. Have I mentioned how much I love Caddy? Only tested on macOS, hopefully works in other environments. --- .vscode/launch.json | 2 +- VERSION | 2 +- pkg/config/config.go | 19 ++++++++++++++++--- pkg/daemon/caddyapi.go | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e561755..1e1571d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "go", "request": "launch", "mode": "debug", - "args": ["daemon", "stop"], + "args": ["daemon", "reload"], "program": "./cmd/localias", } diff --git a/VERSION b/VERSION index 3eefcb9..7dea76e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +1.0.1 diff --git a/pkg/config/config.go b/pkg/config/config.go index fa3a5ae..2a4125d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -166,6 +166,18 @@ func (c *Config) Save() error { return os.WriteFile(c.Path, bytes, 0o644) } +func (c Config) CaddySocketPath() string { + path, err := xdg.StateFile("localias/caddy.sock") + if err != nil { + panic(err) + } + path, err = filepath.Abs(path) + if err != nil { + panic(err) + } + return "unix/" + path +} + func (c Config) CaddyStatePath() string { path, err := xdg.StateFile("localias/caddy") if err != nil { @@ -179,12 +191,13 @@ func (c Config) CaddyStatePath() string { } func (c Config) Caddyfile() string { - path := c.CaddyStatePath() + socketPath := c.CaddySocketPath() + statePath := c.CaddyStatePath() // TODO: take an admin port/interface as part of the config settings, and also // as part of the CLI? global := fmt.Sprintf(strings.TrimSpace(` { - admin localhost:2019 + admin "%s" persist_config off local_certs ocsp_stapling off @@ -197,7 +210,7 @@ func (c Config) Caddyfile() string { } } } -`), path) +`), socketPath, statePath) blocks := []string{global} for _, x := range c.Entries { blocks = append(blocks, x.Caddyfile()) diff --git a/pkg/daemon/caddyapi.go b/pkg/daemon/caddyapi.go index bf3be9e..983ea9c 100644 --- a/pkg/daemon/caddyapi.go +++ b/pkg/daemon/caddyapi.go @@ -29,7 +29,7 @@ func determineAPIAddress(cfg *config.Config) (string, error) { if err != nil { return "", fmt.Errorf("failed to parse configuration: %w", err) } - address, err := caddycmd.DetermineAdminAPIAddress("", cfgJSON, "", "") + address, err := caddycmd.DetermineAdminAPIAddress("", cfgJSON, caddyfile, "caddyfile") if err != nil { return "", fmt.Errorf("could not determine api address: %w", err) }