Browse Source
* httpcaddyfile: First pass at implementing server options * httpcaddyfile: Add listener wrapper support * httpcaddyfile: Sort sbaddrs to make adapt output more deterministic * httpcaddyfile: Add server options adapt tests * httpcaddyfile: Windows line endings lol * caddytest: More windows line endings lol (sorry Matt) * Update caddyconfig/httpcaddyfile/serveroptions.go Co-authored-by: Matt Holt <mholt@users.noreply.github.com> * httpcaddyfile: Reword listener address "matcher" * Apply suggestions from code review Co-authored-by: Matt Holt <mholt@users.noreply.github.com> * httpcaddyfile: Deprecate experimental_http3 option (moved to servers) * httpcaddyfile: Remove validation step, no longer needed Co-authored-by: Matt Holt <mholt@users.noreply.github.com>master
committed by
GitHub
15 changed files with 1084 additions and 658 deletions
@ -0,0 +1,235 @@ |
|||||
|
// Copyright 2015 Matthew Holt and The Caddy Authors
|
||||
|
//
|
||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
// you may not use this file except in compliance with the License.
|
||||
|
// You may obtain a copy of the License at
|
||||
|
//
|
||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
//
|
||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
// See the License for the specific language governing permissions and
|
||||
|
// limitations under the License.
|
||||
|
|
||||
|
package httpcaddyfile |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
|
||||
|
"github.com/caddyserver/caddy/v2" |
||||
|
"github.com/caddyserver/caddy/v2/caddyconfig" |
||||
|
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" |
||||
|
"github.com/caddyserver/caddy/v2/modules/caddyhttp" |
||||
|
"github.com/dustin/go-humanize" |
||||
|
) |
||||
|
|
||||
|
// serverOptions collects server config overrides parsed from Caddyfile global options
|
||||
|
type serverOptions struct { |
||||
|
// If set, will only apply these options to servers that contain a
|
||||
|
// listener address that matches exactly. If empty, will apply to all
|
||||
|
// servers that were not already matched by another serverOptions.
|
||||
|
ListenerAddress string |
||||
|
|
||||
|
// These will all map 1:1 to the caddyhttp.Server struct
|
||||
|
ListenerWrappersRaw []json.RawMessage |
||||
|
ReadTimeout caddy.Duration |
||||
|
ReadHeaderTimeout caddy.Duration |
||||
|
WriteTimeout caddy.Duration |
||||
|
IdleTimeout caddy.Duration |
||||
|
MaxHeaderBytes int |
||||
|
AllowH2C bool |
||||
|
ExperimentalHTTP3 bool |
||||
|
StrictSNIHost *bool |
||||
|
} |
||||
|
|
||||
|
func unmarshalCaddyfileServerOptions(d *caddyfile.Dispenser) (interface{}, error) { |
||||
|
serverOpts := serverOptions{} |
||||
|
for d.Next() { |
||||
|
if d.NextArg() { |
||||
|
serverOpts.ListenerAddress = d.Val() |
||||
|
if d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
} |
||||
|
for nesting := d.Nesting(); d.NextBlock(nesting); { |
||||
|
switch d.Val() { |
||||
|
case "listener_wrappers": |
||||
|
for nesting := d.Nesting(); d.NextBlock(nesting); { |
||||
|
mod, err := caddy.GetModule("caddy.listeners." + d.Val()) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("finding listener module '%s': %v", d.Val(), err) |
||||
|
} |
||||
|
unm, ok := mod.New().(caddyfile.Unmarshaler) |
||||
|
if !ok { |
||||
|
return nil, fmt.Errorf("listener module '%s' is not a Caddyfile unmarshaler", mod) |
||||
|
} |
||||
|
err = unm.UnmarshalCaddyfile(d.NewFromNextSegment()) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
listenerWrapper, ok := unm.(caddy.ListenerWrapper) |
||||
|
if !ok { |
||||
|
return nil, fmt.Errorf("module %s is not a listener wrapper", mod) |
||||
|
} |
||||
|
jsonListenerWrapper := caddyconfig.JSONModuleObject( |
||||
|
listenerWrapper, |
||||
|
"wrapper", |
||||
|
listenerWrapper.(caddy.Module).CaddyModule().ID.Name(), |
||||
|
nil, |
||||
|
) |
||||
|
serverOpts.ListenerWrappersRaw = append(serverOpts.ListenerWrappersRaw, jsonListenerWrapper) |
||||
|
} |
||||
|
|
||||
|
case "timeouts": |
||||
|
for nesting := d.Nesting(); d.NextBlock(nesting); { |
||||
|
switch d.Val() { |
||||
|
case "read_body": |
||||
|
if !d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
dur, err := caddy.ParseDuration(d.Val()) |
||||
|
if err != nil { |
||||
|
return nil, d.Errf("parsing read_body timeout duration: %v", err) |
||||
|
} |
||||
|
serverOpts.ReadTimeout = caddy.Duration(dur) |
||||
|
|
||||
|
case "read_header": |
||||
|
if !d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
dur, err := caddy.ParseDuration(d.Val()) |
||||
|
if err != nil { |
||||
|
return nil, d.Errf("parsing read_header timeout duration: %v", err) |
||||
|
} |
||||
|
serverOpts.ReadHeaderTimeout = caddy.Duration(dur) |
||||
|
|
||||
|
case "write": |
||||
|
if !d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
dur, err := caddy.ParseDuration(d.Val()) |
||||
|
if err != nil { |
||||
|
return nil, d.Errf("parsing write timeout duration: %v", err) |
||||
|
} |
||||
|
serverOpts.WriteTimeout = caddy.Duration(dur) |
||||
|
|
||||
|
case "idle": |
||||
|
if !d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
dur, err := caddy.ParseDuration(d.Val()) |
||||
|
if err != nil { |
||||
|
return nil, d.Errf("parsing idle timeout duration: %v", err) |
||||
|
} |
||||
|
serverOpts.IdleTimeout = caddy.Duration(dur) |
||||
|
|
||||
|
default: |
||||
|
return nil, d.Errf("unrecognized timeouts option '%s'", d.Val()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
case "max_header_size": |
||||
|
var sizeStr string |
||||
|
if !d.AllArgs(&sizeStr) { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
size, err := humanize.ParseBytes(sizeStr) |
||||
|
if err != nil { |
||||
|
return nil, d.Errf("parsing max_header_size: %v", err) |
||||
|
} |
||||
|
serverOpts.MaxHeaderBytes = int(size) |
||||
|
|
||||
|
case "protocol": |
||||
|
for nesting := d.Nesting(); d.NextBlock(nesting); { |
||||
|
switch d.Val() { |
||||
|
case "allow_h2c": |
||||
|
if d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
serverOpts.AllowH2C = true |
||||
|
|
||||
|
case "experimental_http3": |
||||
|
if d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
serverOpts.ExperimentalHTTP3 = true |
||||
|
|
||||
|
case "strict_sni_host": |
||||
|
if d.NextArg() { |
||||
|
return nil, d.ArgErr() |
||||
|
} |
||||
|
trueBool := true |
||||
|
serverOpts.StrictSNIHost = &trueBool |
||||
|
|
||||
|
default: |
||||
|
return nil, d.Errf("unrecognized protocol option '%s'", d.Val()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
default: |
||||
|
return nil, d.Errf("unrecognized servers option '%s'", d.Val()) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return serverOpts, nil |
||||
|
} |
||||
|
|
||||
|
// applyServerOptions sets the server options on the appropriate servers
|
||||
|
func applyServerOptions( |
||||
|
servers map[string]*caddyhttp.Server, |
||||
|
options map[string]interface{}, |
||||
|
warnings *[]caddyconfig.Warning, |
||||
|
) error { |
||||
|
// If experimental HTTP/3 is enabled, enable it on each server.
|
||||
|
// We already know there won't be a conflict with serverOptions because
|
||||
|
// we validated earlier that "experimental_http3" cannot be set at the same
|
||||
|
// time as "servers"
|
||||
|
if enableH3, ok := options["experimental_http3"].(bool); ok && enableH3 { |
||||
|
*warnings = append(*warnings, caddyconfig.Warning{Message: "the 'experimental_http3' global option is deprecated, please use the 'servers > protocol > experimental_http3' option instead"}) |
||||
|
for _, srv := range servers { |
||||
|
srv.ExperimentalHTTP3 = true |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
serverOpts, ok := options["servers"].([]serverOptions) |
||||
|
if !ok { |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
for _, server := range servers { |
||||
|
// find the options that apply to this server
|
||||
|
opts := func() *serverOptions { |
||||
|
for _, entry := range serverOpts { |
||||
|
if entry.ListenerAddress == "" { |
||||
|
return &entry |
||||
|
} |
||||
|
for _, listener := range server.Listen { |
||||
|
if entry.ListenerAddress == listener { |
||||
|
return &entry |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return nil |
||||
|
}() |
||||
|
|
||||
|
// if none apply, then move to the next server
|
||||
|
if opts == nil { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
// set all the options
|
||||
|
server.ListenerWrappersRaw = opts.ListenerWrappersRaw |
||||
|
server.ReadTimeout = opts.ReadTimeout |
||||
|
server.ReadHeaderTimeout = opts.ReadHeaderTimeout |
||||
|
server.WriteTimeout = opts.WriteTimeout |
||||
|
server.IdleTimeout = opts.IdleTimeout |
||||
|
server.MaxHeaderBytes = opts.MaxHeaderBytes |
||||
|
server.AllowH2C = opts.AllowH2C |
||||
|
server.ExperimentalHTTP3 = opts.ExperimentalHTTP3 |
||||
|
server.StrictSNIHost = opts.StrictSNIHost |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
@ -0,0 +1,83 @@ |
|||||
|
{ |
||||
|
servers { |
||||
|
timeouts { |
||||
|
idle 90s |
||||
|
} |
||||
|
} |
||||
|
servers :80 { |
||||
|
timeouts { |
||||
|
idle 60s |
||||
|
} |
||||
|
} |
||||
|
servers :443 { |
||||
|
timeouts { |
||||
|
idle 30s |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
foo.com { |
||||
|
} |
||||
|
|
||||
|
http://bar.com { |
||||
|
} |
||||
|
|
||||
|
:8080 { |
||||
|
} |
||||
|
|
||||
|
---------- |
||||
|
{ |
||||
|
"apps": { |
||||
|
"http": { |
||||
|
"servers": { |
||||
|
"srv0": { |
||||
|
"listen": [ |
||||
|
":443" |
||||
|
], |
||||
|
"idle_timeout": 30000000000, |
||||
|
"routes": [ |
||||
|
{ |
||||
|
"match": [ |
||||
|
{ |
||||
|
"host": [ |
||||
|
"foo.com" |
||||
|
] |
||||
|
} |
||||
|
], |
||||
|
"terminal": true |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
"srv1": { |
||||
|
"listen": [ |
||||
|
":80" |
||||
|
], |
||||
|
"idle_timeout": 60000000000, |
||||
|
"routes": [ |
||||
|
{ |
||||
|
"match": [ |
||||
|
{ |
||||
|
"host": [ |
||||
|
"bar.com" |
||||
|
] |
||||
|
} |
||||
|
], |
||||
|
"terminal": true |
||||
|
} |
||||
|
], |
||||
|
"automatic_https": { |
||||
|
"skip": [ |
||||
|
"bar.com" |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
"srv2": { |
||||
|
"listen": [ |
||||
|
":8080" |
||||
|
], |
||||
|
"idle_timeout": 90000000000 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
{ |
||||
|
servers { |
||||
|
listener_wrappers { |
||||
|
tls |
||||
|
} |
||||
|
timeouts { |
||||
|
read_body 30s |
||||
|
read_header 30s |
||||
|
write 30s |
||||
|
idle 30s |
||||
|
} |
||||
|
max_header_size 100MB |
||||
|
protocol { |
||||
|
allow_h2c |
||||
|
experimental_http3 |
||||
|
strict_sni_host |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
foo.com { |
||||
|
} |
||||
|
|
||||
|
---------- |
||||
|
{ |
||||
|
"apps": { |
||||
|
"http": { |
||||
|
"servers": { |
||||
|
"srv0": { |
||||
|
"listen": [ |
||||
|
":443" |
||||
|
], |
||||
|
"listener_wrappers": [ |
||||
|
{ |
||||
|
"wrapper": "tls" |
||||
|
} |
||||
|
], |
||||
|
"read_timeout": 30000000000, |
||||
|
"read_header_timeout": 30000000000, |
||||
|
"write_timeout": 30000000000, |
||||
|
"idle_timeout": 30000000000, |
||||
|
"max_header_bytes": 100000000, |
||||
|
"routes": [ |
||||
|
{ |
||||
|
"match": [ |
||||
|
{ |
||||
|
"host": [ |
||||
|
"foo.com" |
||||
|
] |
||||
|
} |
||||
|
], |
||||
|
"terminal": true |
||||
|
} |
||||
|
], |
||||
|
"strict_sni_host": true, |
||||
|
"experimental_http3": true, |
||||
|
"allow_h2c": true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,52 +1,52 @@ |
|||||
:80 |
:80 |
||||
handle_path /api/v1/* { |
handle_path /api/v1/* { |
||||
respond "API v1" |
respond "API v1" |
||||
} |
} |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":80" |
":80" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"/api/v1/*" |
"/api/v1/*" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "rewrite", |
"handler": "rewrite", |
||||
"strip_path_prefix": "/api/v1" |
"strip_path_prefix": "/api/v1" |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"body": "API v1", |
"body": "API v1", |
||||
"handler": "static_response" |
"handler": "static_response" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,105 +1,105 @@ |
|||||
:80 { |
:80 { |
||||
handle /api/* { |
handle /api/* { |
||||
respond "api" |
respond "api" |
||||
} |
} |
||||
|
|
||||
handle_path /static/* { |
handle_path /static/* { |
||||
respond "static" |
respond "static" |
||||
} |
} |
||||
|
|
||||
handle { |
handle { |
||||
respond "handle" |
respond "handle" |
||||
} |
} |
||||
} |
} |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":80" |
":80" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"group": "group3", |
"group": "group3", |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"/static/*" |
"/static/*" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "rewrite", |
"handler": "rewrite", |
||||
"strip_path_prefix": "/static" |
"strip_path_prefix": "/static" |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"body": "static", |
"body": "static", |
||||
"handler": "static_response" |
"handler": "static_response" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"group": "group3", |
"group": "group3", |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"/api/*" |
"/api/*" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"body": "api", |
"body": "api", |
||||
"handler": "static_response" |
"handler": "static_response" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"group": "group3", |
"group": "group3", |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"body": "handle", |
"body": "handle", |
||||
"handler": "static_response" |
"handler": "static_response" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,49 +1,49 @@ |
|||||
example.com |
example.com |
||||
|
|
||||
import testdata/import_respond.txt Groot Rocket |
import testdata/import_respond.txt Groot Rocket |
||||
import testdata/import_respond.txt you "the confused man" |
import testdata/import_respond.txt you "the confused man" |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":443" |
":443" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"host": [ |
"host": [ |
||||
"example.com" |
"example.com" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"body": "'I am Groot', hears Rocket", |
"body": "'I am Groot', hears Rocket", |
||||
"handler": "static_response" |
"handler": "static_response" |
||||
}, |
}, |
||||
{ |
{ |
||||
"body": "'I am you', hears the confused man", |
"body": "'I am you', hears the confused man", |
||||
"handler": "static_response" |
"handler": "static_response" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"terminal": true |
"terminal": true |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,83 +1,83 @@ |
|||||
(logging) { |
(logging) { |
||||
log { |
log { |
||||
output file /var/log/caddy/{args.0}.access.log |
output file /var/log/caddy/{args.0}.access.log |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
a.example.com { |
a.example.com { |
||||
import logging a.example.com |
import logging a.example.com |
||||
} |
} |
||||
|
|
||||
b.example.com { |
b.example.com { |
||||
import logging b.example.com |
import logging b.example.com |
||||
} |
} |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"logging": { |
"logging": { |
||||
"logs": { |
"logs": { |
||||
"default": { |
"default": { |
||||
"exclude": [ |
"exclude": [ |
||||
"http.log.access.log0", |
"http.log.access.log0", |
||||
"http.log.access.log1" |
"http.log.access.log1" |
||||
] |
] |
||||
}, |
}, |
||||
"log0": { |
"log0": { |
||||
"writer": { |
"writer": { |
||||
"filename": "/var/log/caddy/a.example.com.access.log", |
"filename": "/var/log/caddy/a.example.com.access.log", |
||||
"output": "file" |
"output": "file" |
||||
}, |
}, |
||||
"include": [ |
"include": [ |
||||
"http.log.access.log0" |
"http.log.access.log0" |
||||
] |
] |
||||
}, |
}, |
||||
"log1": { |
"log1": { |
||||
"writer": { |
"writer": { |
||||
"filename": "/var/log/caddy/b.example.com.access.log", |
"filename": "/var/log/caddy/b.example.com.access.log", |
||||
"output": "file" |
"output": "file" |
||||
}, |
}, |
||||
"include": [ |
"include": [ |
||||
"http.log.access.log1" |
"http.log.access.log1" |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
}, |
}, |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":443" |
":443" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"host": [ |
"host": [ |
||||
"a.example.com" |
"a.example.com" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"terminal": true |
"terminal": true |
||||
}, |
}, |
||||
{ |
{ |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"host": [ |
"host": [ |
||||
"b.example.com" |
"b.example.com" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"terminal": true |
"terminal": true |
||||
} |
} |
||||
], |
], |
||||
"logs": { |
"logs": { |
||||
"logger_names": { |
"logger_names": { |
||||
"a.example.com": "log0", |
"a.example.com": "log0", |
||||
"b.example.com": "log1" |
"b.example.com": "log1" |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,69 +1,69 @@ |
|||||
:80 |
:80 |
||||
|
|
||||
log { |
log { |
||||
output stdout |
output stdout |
||||
format filter { |
format filter { |
||||
wrap console |
wrap console |
||||
fields { |
fields { |
||||
request>headers>Authorization delete |
request>headers>Authorization delete |
||||
request>headers>Server delete |
request>headers>Server delete |
||||
request>remote_addr ip_mask { |
request>remote_addr ip_mask { |
||||
ipv4 24 |
ipv4 24 |
||||
ipv6 32 |
ipv6 32 |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"logging": { |
"logging": { |
||||
"logs": { |
"logs": { |
||||
"default": { |
"default": { |
||||
"exclude": [ |
"exclude": [ |
||||
"http.log.access.log0" |
"http.log.access.log0" |
||||
] |
] |
||||
}, |
}, |
||||
"log0": { |
"log0": { |
||||
"writer": { |
"writer": { |
||||
"output": "stdout" |
"output": "stdout" |
||||
}, |
}, |
||||
"encoder": { |
"encoder": { |
||||
"fields": { |
"fields": { |
||||
"request\u003eheaders\u003eAuthorization": { |
"request\u003eheaders\u003eAuthorization": { |
||||
"filter": "delete" |
"filter": "delete" |
||||
}, |
}, |
||||
"request\u003eheaders\u003eServer": { |
"request\u003eheaders\u003eServer": { |
||||
"filter": "delete" |
"filter": "delete" |
||||
}, |
}, |
||||
"request\u003eremote_addr": { |
"request\u003eremote_addr": { |
||||
"filter": "ip_mask", |
"filter": "ip_mask", |
||||
"ipv4_cidr": 24, |
"ipv4_cidr": 24, |
||||
"ipv6_cidr": 32 |
"ipv6_cidr": 32 |
||||
} |
} |
||||
}, |
}, |
||||
"format": "filter", |
"format": "filter", |
||||
"wrap": { |
"wrap": { |
||||
"format": "console" |
"format": "console" |
||||
} |
} |
||||
}, |
}, |
||||
"include": [ |
"include": [ |
||||
"http.log.access.log0" |
"http.log.access.log0" |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
}, |
}, |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":80" |
":80" |
||||
], |
], |
||||
"logs": { |
"logs": { |
||||
"default_logger_name": "log0" |
"default_logger_name": "log0" |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,132 +1,132 @@ |
|||||
:8886 |
:8886 |
||||
|
|
||||
route { |
route { |
||||
# Add trailing slash for directory requests |
# Add trailing slash for directory requests |
||||
@canonicalPath { |
@canonicalPath { |
||||
file { |
file { |
||||
try_files {path}/index.php |
try_files {path}/index.php |
||||
} |
} |
||||
not path */ |
not path */ |
||||
} |
} |
||||
redir @canonicalPath {path}/ 308 |
redir @canonicalPath {path}/ 308 |
||||
|
|
||||
# If the requested file does not exist, try index files |
# If the requested file does not exist, try index files |
||||
@indexFiles { |
@indexFiles { |
||||
file { |
file { |
||||
try_files {path} {path}/index.php index.php |
try_files {path} {path}/index.php index.php |
||||
split_path .php |
split_path .php |
||||
} |
} |
||||
} |
} |
||||
rewrite @indexFiles {http.matchers.file.relative} |
rewrite @indexFiles {http.matchers.file.relative} |
||||
|
|
||||
# Proxy PHP files to the FastCGI responder |
# Proxy PHP files to the FastCGI responder |
||||
@phpFiles { |
@phpFiles { |
||||
path *.php |
path *.php |
||||
} |
} |
||||
reverse_proxy @phpFiles 127.0.0.1:9000 { |
reverse_proxy @phpFiles 127.0.0.1:9000 { |
||||
transport fastcgi { |
transport fastcgi { |
||||
split .php |
split .php |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":8886" |
":8886" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "static_response", |
"handler": "static_response", |
||||
"headers": { |
"headers": { |
||||
"Location": [ |
"Location": [ |
||||
"{http.request.uri.path}/" |
"{http.request.uri.path}/" |
||||
] |
] |
||||
}, |
}, |
||||
"status_code": 308 |
"status_code": 308 |
||||
} |
} |
||||
], |
], |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"file": { |
"file": { |
||||
"try_files": [ |
"try_files": [ |
||||
"{http.request.uri.path}/index.php" |
"{http.request.uri.path}/index.php" |
||||
] |
] |
||||
}, |
}, |
||||
"not": [ |
"not": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"*/" |
"*/" |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "rewrite", |
"handler": "rewrite", |
||||
"uri": "{http.matchers.file.relative}" |
"uri": "{http.matchers.file.relative}" |
||||
} |
} |
||||
], |
], |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"file": { |
"file": { |
||||
"split_path": [ |
"split_path": [ |
||||
".php" |
".php" |
||||
], |
], |
||||
"try_files": [ |
"try_files": [ |
||||
"{http.request.uri.path}", |
"{http.request.uri.path}", |
||||
"{http.request.uri.path}/index.php", |
"{http.request.uri.path}/index.php", |
||||
"index.php" |
"index.php" |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "reverse_proxy", |
"handler": "reverse_proxy", |
||||
"transport": { |
"transport": { |
||||
"protocol": "fastcgi", |
"protocol": "fastcgi", |
||||
"split_path": [ |
"split_path": [ |
||||
".php" |
".php" |
||||
] |
] |
||||
}, |
}, |
||||
"upstreams": [ |
"upstreams": [ |
||||
{ |
{ |
||||
"dial": "127.0.0.1:9000" |
"dial": "127.0.0.1:9000" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"*.php" |
"*.php" |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,112 +1,112 @@ |
|||||
:8884 |
:8884 |
||||
|
|
||||
@api host example.com |
@api host example.com |
||||
php_fastcgi @api localhost:9000 |
php_fastcgi @api localhost:9000 |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":8884" |
":8884" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"host": [ |
"host": [ |
||||
"example.com" |
"example.com" |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "subroute", |
"handler": "subroute", |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "static_response", |
"handler": "static_response", |
||||
"headers": { |
"headers": { |
||||
"Location": [ |
"Location": [ |
||||
"{http.request.uri.path}/" |
"{http.request.uri.path}/" |
||||
] |
] |
||||
}, |
}, |
||||
"status_code": 308 |
"status_code": 308 |
||||
} |
} |
||||
], |
], |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"file": { |
"file": { |
||||
"try_files": [ |
"try_files": [ |
||||
"{http.request.uri.path}/index.php" |
"{http.request.uri.path}/index.php" |
||||
] |
] |
||||
}, |
}, |
||||
"not": [ |
"not": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"*/" |
"*/" |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "rewrite", |
"handler": "rewrite", |
||||
"uri": "{http.matchers.file.relative}" |
"uri": "{http.matchers.file.relative}" |
||||
} |
} |
||||
], |
], |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"file": { |
"file": { |
||||
"split_path": [ |
"split_path": [ |
||||
".php" |
".php" |
||||
], |
], |
||||
"try_files": [ |
"try_files": [ |
||||
"{http.request.uri.path}", |
"{http.request.uri.path}", |
||||
"{http.request.uri.path}/index.php", |
"{http.request.uri.path}/index.php", |
||||
"index.php" |
"index.php" |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "reverse_proxy", |
"handler": "reverse_proxy", |
||||
"transport": { |
"transport": { |
||||
"protocol": "fastcgi", |
"protocol": "fastcgi", |
||||
"split_path": [ |
"split_path": [ |
||||
".php" |
".php" |
||||
] |
] |
||||
}, |
}, |
||||
"upstreams": [ |
"upstreams": [ |
||||
{ |
{ |
||||
"dial": "localhost:9000" |
"dial": "localhost:9000" |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"path": [ |
"path": [ |
||||
"*.php" |
"*.php" |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
@ -1,51 +1,51 @@ |
|||||
:80 |
:80 |
||||
|
|
||||
respond 200 |
respond 200 |
||||
|
|
||||
@untrusted not remote_ip 10.1.1.0/24 |
@untrusted not remote_ip 10.1.1.0/24 |
||||
respond @untrusted 401 |
respond @untrusted 401 |
||||
---------- |
---------- |
||||
{ |
{ |
||||
"apps": { |
"apps": { |
||||
"http": { |
"http": { |
||||
"servers": { |
"servers": { |
||||
"srv0": { |
"srv0": { |
||||
"listen": [ |
"listen": [ |
||||
":80" |
":80" |
||||
], |
], |
||||
"routes": [ |
"routes": [ |
||||
{ |
{ |
||||
"match": [ |
"match": [ |
||||
{ |
{ |
||||
"not": [ |
"not": [ |
||||
{ |
{ |
||||
"remote_ip": { |
"remote_ip": { |
||||
"ranges": [ |
"ranges": [ |
||||
"10.1.1.0/24" |
"10.1.1.0/24" |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
], |
], |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "static_response", |
"handler": "static_response", |
||||
"status_code": 401 |
"status_code": 401 |
||||
} |
} |
||||
] |
] |
||||
}, |
}, |
||||
{ |
{ |
||||
"handle": [ |
"handle": [ |
||||
{ |
{ |
||||
"handler": "static_response", |
"handler": "static_response", |
||||
"status_code": 200 |
"status_code": 200 |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
] |
] |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
Loading…
Reference in new issue