diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 00678ef2..43d756f6 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -706,7 +706,7 @@ func (st *ServerType) serversFromPairings( err := applyServerOptions(servers, options, warnings) if err != nil { - return nil, err + return nil, fmt.Errorf("applying global server options: %v", err) } return servers, nil diff --git a/caddyconfig/httpcaddyfile/serveroptions.go b/caddyconfig/httpcaddyfile/serveroptions.go index 7aa0a2a8..dca4ede7 100644 --- a/caddyconfig/httpcaddyfile/serveroptions.go +++ b/caddyconfig/httpcaddyfile/serveroptions.go @@ -33,6 +33,7 @@ type serverOptions struct { ListenerAddress string // These will all map 1:1 to the caddyhttp.Server struct + Name string ListenerWrappersRaw []json.RawMessage ReadTimeout caddy.Duration ReadHeaderTimeout caddy.Duration @@ -58,6 +59,15 @@ func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (any, error) { } for nesting := d.Nesting(); d.NextBlock(nesting); { switch d.Val() { + case "name": + if serverOpts.ListenerAddress == "" { + return nil, d.Errf("cannot set a name for a server without a listener address") + } + if !d.NextArg() { + return nil, d.ArgErr() + } + serverOpts.Name = d.Val() + case "listener_wrappers": for nesting := d.Nesting(); d.NextBlock(nesting); { modID := "caddy.listeners." + d.Val() @@ -248,7 +258,22 @@ func applyServerOptions( return nil } - for _, server := range servers { + // check for duplicate names, which would clobber the config + existingNames := map[string]bool{} + for _, opts := range serverOpts { + if opts.Name == "" { + continue + } + if existingNames[opts.Name] { + return fmt.Errorf("cannot use duplicate server name '%s'", opts.Name) + } + existingNames[opts.Name] = true + } + + // collect the server name overrides + nameReplacements := map[string]string{} + + for key, server := range servers { // find the options that apply to this server opts := func() *serverOptions { for _, entry := range serverOpts { @@ -287,6 +312,16 @@ func applyServerOptions( } server.Logs.ShouldLogCredentials = opts.ShouldLogCredentials } + + if opts.Name != "" { + nameReplacements[key] = opts.Name + } + } + + // rename the servers if marked to do so + for old, new := range nameReplacements { + servers[new] = servers[old] + delete(servers, old) } return nil diff --git a/caddytest/integration/caddyfile_adapt/server_names.txt b/caddytest/integration/caddyfile_adapt/server_names.txt new file mode 100644 index 00000000..e43eb8c0 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/server_names.txt @@ -0,0 +1,77 @@ +{ + servers :443 { + name https + } + + servers :8000 { + name app1 + } + + servers :8001 { + name app2 + } + + servers 123.123.123.123:8002 { + name bind-server + } +} + +example.com { +} + +:8000 { +} + +:8001, :8002 { +} + +:8002 { + bind 123.123.123.123 222.222.222.222 +} +---------- +{ + "apps": { + "http": { + "servers": { + "app1": { + "listen": [ + ":8000" + ] + }, + "app2": { + "listen": [ + ":8001" + ] + }, + "bind-server": { + "listen": [ + "123.123.123.123:8002", + "222.222.222.222:8002" + ] + }, + "https": { + "listen": [ + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "example.com" + ] + } + ], + "terminal": true + } + ] + }, + "srv4": { + "listen": [ + ":8002" + ] + } + } + } + } +} \ No newline at end of file