2015-01-14 03:43:45 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2015-01-14 07:14:00 +08:00
|
|
|
"flag"
|
2015-04-16 04:11:32 +08:00
|
|
|
"fmt"
|
2015-01-14 03:43:45 +08:00
|
|
|
"log"
|
2015-04-16 04:11:32 +08:00
|
|
|
"net"
|
2015-01-14 03:43:45 +08:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/mholt/caddy/config"
|
|
|
|
"github.com/mholt/caddy/server"
|
|
|
|
)
|
|
|
|
|
2015-04-10 00:08:22 +08:00
|
|
|
var (
|
|
|
|
conf string
|
2015-04-24 03:28:05 +08:00
|
|
|
http2 bool // TODO: temporary flag until http2 is standard
|
|
|
|
quiet bool
|
2015-04-10 00:08:22 +08:00
|
|
|
)
|
2015-01-19 14:11:21 +08:00
|
|
|
|
|
|
|
func init() {
|
2015-04-16 04:11:32 +08:00
|
|
|
flag.StringVar(&conf, "conf", config.DefaultConfigFile, "the configuration file to use")
|
2015-04-24 03:28:05 +08:00
|
|
|
flag.BoolVar(&http2, "http2", true, "enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib
|
|
|
|
flag.BoolVar(&quiet, "quiet", false, "quiet mode (no initialization output)")
|
|
|
|
flag.Parse()
|
2015-01-19 14:11:21 +08:00
|
|
|
}
|
|
|
|
|
2015-01-14 03:43:45 +08:00
|
|
|
func main() {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
2015-04-16 04:11:32 +08:00
|
|
|
// Load config from file
|
|
|
|
allConfigs, err := config.Load(conf)
|
2015-01-14 03:43:45 +08:00
|
|
|
if err != nil {
|
|
|
|
if config.IsNotFound(err) {
|
2015-04-16 04:11:32 +08:00
|
|
|
allConfigs = config.Default()
|
2015-01-14 03:43:45 +08:00
|
|
|
} else {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2015-04-18 23:53:43 +08:00
|
|
|
if len(allConfigs) == 0 {
|
|
|
|
allConfigs = config.Default()
|
|
|
|
}
|
2015-01-14 03:43:45 +08:00
|
|
|
|
2015-04-18 23:53:43 +08:00
|
|
|
// Group by address (virtual hosts)
|
2015-04-16 04:11:32 +08:00
|
|
|
addresses, err := arrangeBindings(allConfigs)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start each server with its one or more configurations
|
|
|
|
for addr, configs := range addresses {
|
|
|
|
s, err := server.New(addr, configs, configs[0].TLS.Enabled)
|
2015-01-14 03:43:45 +08:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-04-12 06:58:34 +08:00
|
|
|
s.HTTP2 = http2 // TODO: This setting is temporary
|
2015-01-14 03:43:45 +08:00
|
|
|
wg.Add(1)
|
|
|
|
go func(s *server.Server) {
|
|
|
|
defer wg.Done()
|
|
|
|
err := s.Serve()
|
|
|
|
if err != nil {
|
2015-03-29 06:24:00 +08:00
|
|
|
log.Println(err)
|
2015-01-14 03:43:45 +08:00
|
|
|
}
|
|
|
|
}(s)
|
2015-04-24 03:28:05 +08:00
|
|
|
|
|
|
|
if !quiet {
|
|
|
|
for _, config := range configs {
|
|
|
|
fmt.Printf("%s -> OK\n", config.Address())
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 03:43:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2015-04-16 04:11:32 +08:00
|
|
|
|
|
|
|
// arrangeBindings groups configurations by their bind address. For example,
|
|
|
|
// a server that should listen on localhost and another on 127.0.0.1 will
|
|
|
|
// be grouped into the same address: 127.0.0.1. It will return an error
|
|
|
|
// if the address lookup fails or if a TLS listener is configured on the
|
|
|
|
// same address as a plaintext HTTP listener.
|
|
|
|
func arrangeBindings(allConfigs []config.Config) (map[string][]config.Config, error) {
|
|
|
|
addresses := make(map[string][]config.Config)
|
|
|
|
|
|
|
|
// Group configs by bind address
|
|
|
|
for _, conf := range allConfigs {
|
|
|
|
addr, err := net.ResolveTCPAddr("tcp", conf.Address())
|
|
|
|
if err != nil {
|
|
|
|
return addresses, err
|
|
|
|
}
|
|
|
|
addresses[addr.String()] = append(addresses[addr.String()], conf)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't allow HTTP and HTTPS to be served on the same address
|
|
|
|
for _, configs := range addresses {
|
|
|
|
isTLS := configs[0].TLS.Enabled
|
|
|
|
for _, config := range configs {
|
|
|
|
if config.TLS.Enabled != isTLS {
|
|
|
|
thisConfigProto, otherConfigProto := "HTTP", "HTTP"
|
|
|
|
if config.TLS.Enabled {
|
|
|
|
thisConfigProto = "HTTPS"
|
|
|
|
}
|
|
|
|
if configs[0].TLS.Enabled {
|
|
|
|
otherConfigProto = "HTTPS"
|
|
|
|
}
|
|
|
|
return addresses, fmt.Errorf("Configuration error: Cannot multiplex %s (%s) and %s (%s) on same address",
|
|
|
|
configs[0].Address(), otherConfigProto, config.Address(), thisConfigProto)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return addresses, nil
|
|
|
|
}
|