mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-26 02:09:47 +08:00
4ebff9a130
Merged config and app packages into one called caddy. Abstracted away caddy startup functionality making it easier to embed Caddy in any Go application and use it as a library. Graceful restart (should) now ensure child starts properly. Now piping a gob bundle to child process so that the child can match up inherited listeners to server address. Much cleanup still to do.
165 lines
3.7 KiB
Go
165 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mholt/caddy/caddy"
|
|
"github.com/mholt/caddy/caddy/letsencrypt"
|
|
)
|
|
|
|
var (
|
|
conf string
|
|
cpu string
|
|
version bool
|
|
revoke string
|
|
)
|
|
|
|
const (
|
|
appName = "Caddy"
|
|
appVersion = "0.8 beta"
|
|
)
|
|
|
|
func init() {
|
|
flag.StringVar(&conf, "conf", "", "Configuration file to use (default="+caddy.DefaultConfigFile+")")
|
|
flag.BoolVar(&caddy.HTTP2, "http2", true, "Enable HTTP/2 support") // TODO: temporary flag until http2 merged into std lib
|
|
flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
|
|
flag.StringVar(&cpu, "cpu", "100%", "CPU cap")
|
|
flag.StringVar(&caddy.Root, "root", caddy.DefaultRoot, "Root path to default site")
|
|
flag.StringVar(&caddy.Host, "host", caddy.DefaultHost, "Default host")
|
|
flag.StringVar(&caddy.Port, "port", caddy.DefaultPort, "Default port")
|
|
flag.BoolVar(&version, "version", false, "Show version")
|
|
flag.BoolVar(&letsencrypt.Agreed, "agree", false, "Agree to Let's Encrypt Subscriber Agreement")
|
|
flag.StringVar(&letsencrypt.DefaultEmail, "email", "", "Default email address to use for Let's Encrypt transactions")
|
|
flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke its certificate")
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
caddy.AppName = appName
|
|
caddy.AppVersion = appVersion
|
|
|
|
if version {
|
|
fmt.Printf("%s %s\n", caddy.AppName, caddy.AppVersion)
|
|
os.Exit(0)
|
|
}
|
|
if revoke != "" {
|
|
err := letsencrypt.Revoke(revoke)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Printf("Revoked certificate for %s\n", revoke)
|
|
os.Exit(0)
|
|
}
|
|
|
|
// Set CPU cap
|
|
err := setCPU(cpu)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Get Caddyfile input
|
|
caddyfile, err := caddy.LoadCaddyfile(loadCaddyfile)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Start your engines
|
|
err = caddy.Start(caddyfile)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// TODO: Temporary; testing restart
|
|
//if os.Getenv("CADDY_RESTART") != "true" {
|
|
go func() {
|
|
time.Sleep(5 * time.Second)
|
|
fmt.Println("restarting")
|
|
log.Println("RESTART ERR:", caddy.Restart(nil))
|
|
}()
|
|
//}
|
|
|
|
// Twiddle your thumbs
|
|
caddy.Wait()
|
|
}
|
|
|
|
func loadCaddyfile() (caddy.Input, error) {
|
|
// -conf flag
|
|
if conf != "" {
|
|
contents, err := ioutil.ReadFile(conf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return caddy.CaddyfileInput{
|
|
Contents: contents,
|
|
Filepath: conf,
|
|
}, nil
|
|
}
|
|
|
|
// command line args
|
|
if flag.NArg() > 0 {
|
|
confBody := ":" + caddy.DefaultPort + "\n" + strings.Join(flag.Args(), "\n")
|
|
return caddy.CaddyfileInput{
|
|
Contents: []byte(confBody),
|
|
Filepath: "args",
|
|
}, nil
|
|
}
|
|
|
|
// Caddyfile in cwd
|
|
contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return caddy.DefaultInput, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return caddy.CaddyfileInput{
|
|
Contents: contents,
|
|
Filepath: caddy.DefaultConfigFile,
|
|
}, nil
|
|
}
|
|
|
|
// setCPU parses string cpu and sets GOMAXPROCS
|
|
// according to its value. It accepts either
|
|
// a number (e.g. 3) or a percent (e.g. 50%).
|
|
func setCPU(cpu string) error {
|
|
var numCPU int
|
|
|
|
availCPU := runtime.NumCPU()
|
|
|
|
if strings.HasSuffix(cpu, "%") {
|
|
// Percent
|
|
var percent float32
|
|
pctStr := cpu[:len(cpu)-1]
|
|
pctInt, err := strconv.Atoi(pctStr)
|
|
if err != nil || pctInt < 1 || pctInt > 100 {
|
|
return errors.New("invalid CPU value: percentage must be between 1-100")
|
|
}
|
|
percent = float32(pctInt) / 100
|
|
numCPU = int(float32(availCPU) * percent)
|
|
} else {
|
|
// Number
|
|
num, err := strconv.Atoi(cpu)
|
|
if err != nil || num < 1 {
|
|
return errors.New("invalid CPU value: provide a number or percent greater than 0")
|
|
}
|
|
numCPU = num
|
|
}
|
|
|
|
if numCPU > availCPU {
|
|
numCPU = availCPU
|
|
}
|
|
|
|
runtime.GOMAXPROCS(numCPU)
|
|
return nil
|
|
}
|