Skip to content

Commit

Permalink
bugfix: switch to unix socket for embedded caddy adminapi
Browse files Browse the repository at this point in the history
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 caddyserver/caddy#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.
  • Loading branch information
peterldowns committed Jul 17, 2023
1 parent 3558267 commit 9fedbac
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"type": "go",
"request": "launch",
"mode": "debug",
"args": ["daemon", "stop"],
"args": ["daemon", "reload"],
"program": "./cmd/localias",

}
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.0.1
19 changes: 16 additions & 3 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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())
Expand Down
2 changes: 1 addition & 1 deletion pkg/daemon/caddyapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down

0 comments on commit 9fedbac

Please sign in to comment.