summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-10-03 16:00:41 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-10-03 16:00:41 -0600
commitc11e3bffd698cfb1e19a21097ff4a65cf10e28b0 (patch)
tree01eb0f52cd3276669677ea32d1859ff0d1398669
parentf29a9eee0d062d7fb975d8779db4ea8a07d26f7d (diff)
Add file-server and reverse-proxy subcommands
-rw-r--r--caddyconfig/httpcaddyfile/addresses.go6
-rw-r--r--modules/caddyhttp/fileserver/command.go106
-rw-r--r--modules/caddyhttp/reverseproxy/command.go138
3 files changed, 248 insertions, 2 deletions
diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go
index 5708783..deb27c2 100644
--- a/caddyconfig/httpcaddyfile/addresses.go
+++ b/caddyconfig/httpcaddyfile/addresses.go
@@ -161,7 +161,7 @@ func (st *ServerType) listenerAddrsForServerBlockKey(sblock serverBlock, key str
}
addr = addr.Normalize()
- lnPort := defaultPort
+ lnPort := DefaultPort
if addr.Port != "" {
// port explicitly defined
lnPort = addr.Port
@@ -327,6 +327,8 @@ func (a Address) Key() string {
}
const (
- defaultPort = "2015"
+ // DefaultPort is the default port to use.
+ DefaultPort = "2015"
+
caseSensitivePath = false // TODO: Used?
)
diff --git a/modules/caddyhttp/fileserver/command.go b/modules/caddyhttp/fileserver/command.go
new file mode 100644
index 0000000..727d7ba
--- /dev/null
+++ b/modules/caddyhttp/fileserver/command.go
@@ -0,0 +1,106 @@
+// 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 fileserver
+
+import (
+ "encoding/json"
+ "flag"
+ "log"
+
+ "github.com/caddyserver/caddy/v2"
+ "github.com/caddyserver/caddy/v2/caddyconfig"
+ caddycmd "github.com/caddyserver/caddy/v2/cmd"
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
+)
+
+func init() {
+ caddycmd.RegisterCommand(caddycmd.Command{
+ Name: "file-server",
+ Func: cmdFileServer,
+ Usage: "[--domain <example.com>] [--path <path>] [--listen <addr>] [--browse]",
+ Short: "Spins up a production-ready file server",
+ Long: `
+A simple but production-ready file server. Useful for quick deployments,
+demos, and development.
+
+If a qualifying hostname is specified with --domain, the server will use
+HTTPS if domain validation succeeds. Ensure A/AAAA records are properly
+configured before using this option.
+
+The listener's socket address can be customized with the --listen flag.
+
+If --browse is enabled, requests for folders without an index file will
+respond with a file listing.`,
+ Flags: func() *flag.FlagSet {
+ fs := flag.NewFlagSet("file-server", flag.ExitOnError)
+ fs.String("domain", "", "Domain name at which to serve the files")
+ fs.String("root", "", "The path to the root of the site")
+ fs.String("listen", "", "The address to which to bind the listener")
+ fs.Bool("browse", false, "Whether to enable directory browsing")
+ return fs
+ }(),
+ })
+}
+
+func cmdFileServer(fs caddycmd.Flags) (int, error) {
+ domain := fs.String("domain")
+ root := fs.String("root")
+ listen := fs.String("listen")
+ browse := fs.Bool("browse")
+
+ handler := FileServer{Root: root}
+ if browse {
+ handler.Browse = new(Browse)
+ }
+
+ route := caddyhttp.Route{
+ HandlersRaw: []json.RawMessage{
+ caddyconfig.JSONModuleObject(handler, "handler", "file_server", nil),
+ },
+ }
+ if domain != "" {
+ route.MatcherSetsRaw = []map[string]json.RawMessage{
+ map[string]json.RawMessage{
+ "host": caddyconfig.JSON(caddyhttp.MatchHost{domain}, nil),
+ },
+ }
+ }
+
+ server := &caddyhttp.Server{
+ Routes: caddyhttp.RouteList{route},
+ }
+ if listen != "" {
+ server.Listen = []string{listen}
+ }
+
+ httpApp := caddyhttp.App{
+ Servers: map[string]*caddyhttp.Server{"static": server},
+ }
+
+ cfg := &caddy.Config{
+ AppsRaw: map[string]json.RawMessage{
+ "http": caddyconfig.JSON(httpApp, nil),
+ },
+ }
+
+ err := caddy.Run(cfg)
+ if err != nil {
+ return caddy.ExitCodeFailedStartup, err
+ }
+
+ log.Println("Caddy 2 serving static files")
+
+ select {}
+}
diff --git a/modules/caddyhttp/reverseproxy/command.go b/modules/caddyhttp/reverseproxy/command.go
new file mode 100644
index 0000000..0a664ed
--- /dev/null
+++ b/modules/caddyhttp/reverseproxy/command.go
@@ -0,0 +1,138 @@
+// 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 reverseproxy
+
+import (
+ "encoding/json"
+ "flag"
+ "log"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/caddyserver/caddy/v2"
+ "github.com/caddyserver/caddy/v2/caddyconfig"
+ "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
+ caddycmd "github.com/caddyserver/caddy/v2/cmd"
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp"
+ "github.com/caddyserver/caddy/v2/modules/caddyhttp/headers"
+ "github.com/mholt/certmagic"
+)
+
+func init() {
+ caddycmd.RegisterCommand(caddycmd.Command{
+ Name: "reverse-proxy",
+ Func: cmdReverseProxy,
+ Usage: "[--from <addr>] [--to <addr>]",
+ Short: "A quick and production-ready reverse proxy",
+ Long: `
+A simple but production-ready reverse proxy. Useful for quick deployments,
+demos, and development.
+
+Simply shuttles HTTP traffic from the --from address to the --to address.
+
+If the --from address has a domain name, Caddy will attempt to serve the
+proxy over HTTPS with a certificate.
+`,
+ Flags: func() *flag.FlagSet {
+ fs := flag.NewFlagSet("file-server", flag.ExitOnError)
+ fs.String("from", "", "Address to receive traffic on")
+ fs.String("to", "", "Upstream address to proxy traffic to")
+ return fs
+ }(),
+ })
+}
+
+func cmdReverseProxy(fs caddycmd.Flags) (int, error) {
+ from := fs.String("from")
+ to := fs.String("to")
+
+ if from == "" {
+ from = "localhost:" + httpcaddyfile.DefaultPort
+ }
+
+ if !strings.Contains(from, "://") {
+ from = "http://" + from
+ }
+
+ fromURL, err := url.Parse(from)
+ if err != nil {
+ fromURL.Host = from
+ }
+
+ toURL, err := url.Parse(to)
+ if err != nil {
+ toURL.Host = to
+ }
+
+ ht := HTTPTransport{}
+ if toURL.Scheme == "https" {
+ ht.TLS = new(TLSConfig)
+ }
+
+ handler := Handler{
+ TransportRaw: caddyconfig.JSONModuleObject(ht, "protocol", "http", nil),
+ Upstreams: UpstreamPool{{Dial: toURL.Host}},
+ Headers: &headers.Handler{
+ Request: &headers.HeaderOps{
+ Set: http.Header{
+ "Host": []string{"{http.handlers.reverse_proxy.upstream.host}"},
+ },
+ },
+ },
+ }
+
+ route := caddyhttp.Route{
+ HandlersRaw: []json.RawMessage{
+ caddyconfig.JSONModuleObject(handler, "handler", "reverse_proxy", nil),
+ },
+ }
+ if fromURL.Hostname() != "" {
+ route.MatcherSetsRaw = []map[string]json.RawMessage{
+ map[string]json.RawMessage{
+ "host": caddyconfig.JSON(caddyhttp.MatchHost{fromURL.Hostname()}, nil),
+ },
+ }
+ }
+
+ listen := ":" + httpcaddyfile.DefaultPort
+ if certmagic.HostQualifies(fromURL.Hostname()) {
+ listen = ":443"
+ }
+
+ server := &caddyhttp.Server{
+ Routes: caddyhttp.RouteList{route},
+ Listen: []string{listen},
+ }
+
+ httpApp := caddyhttp.App{
+ Servers: map[string]*caddyhttp.Server{"proxy": server},
+ }
+
+ cfg := &caddy.Config{
+ AppsRaw: map[string]json.RawMessage{
+ "http": caddyconfig.JSON(httpApp, nil),
+ },
+ }
+
+ err = caddy.Run(cfg)
+ if err != nil {
+ return caddy.ExitCodeFailedStartup, err
+ }
+
+ log.Printf("Caddy 2 proxying from %s to %s", from, to)
+
+ select {}
+}