安装

Linux

Note: You must specify a personal or commercial license; see getcaddy.com for instructions. (安装时要求必须给出一种许可证,所以下面命令添加了选项:-s personal)

1
2
3
4
5
# 一键安装脚本
[zhe@zhe Temp]$ curl https://getcaddy.com | bash -s personal 

# 查看文件安装路径
[zhe@zhe Temp]$ which caddy

Windows

download

  • platform 选择需要安装的平台

  • plugins 选择需要的插件(可以不选)

  • 下载完成后解压即可得到 caddy.exe

Source code

源码 安装

1
go get github.com/mholt/caddy/caddy

Note: 从源码安装参考

返回目录

运行

以 Linux 平台作测试

1
2
3
4
5
6
7
8
9
# 直接运行即可
[zhe@zhe Temp]$ caddy
Activating privacy features... done.
http://:2015

# Output: visit http://:2015, got 404 Not Found 则表示成功

# 从指定的 Caddyfile 中读取配置启动服务
[zhe@zhe Temp]$ caddy -conf /path/to/Caddyfile

Note: caddy 从当前目录的 Caddyfile(默认) 文件中读取配置; 也可以通过 -conf 指定配置文件路径

返回目录

应用(配置Caddy)

官方文档Caddyfile Primer(入门书)Caddyfile Directive(指令介绍)

Caddyfile格式: Caddyfile 总是以站点的 Addr 开始, # 表示注释;且之后的每一行都是官方提供的指令

静态文件 Server

文件目录结构

1
2
3
4
5
6
7
8
[root@qxs /home/caddy/test]$ tree
.
├── caddy
├── Caddyfile
├── test
│   └── test.txt
├── test01.txt
└── test02.txt

Caddyfile 内容:

1
2
3
4
localhost:7055 {
    root ./ 
    browse  # 支持浏览文件
}

Note: 对于静态文件Server,caddy支持在website的root路径下首先查找是否有如下四个文件:

1
2
3
4
5
6
7
// caddy/middleware/browse/browse.go
var IndexPages = []string{
    "index.html",
    "index.htm",
    "default.html",
    "default.htm",
}
  • 如果查到有其中一个,则优先返回这个文件内容,这就是静态站点的首页。

  • 如果要支持目录文件列表浏览,则需要为 website 配置 browse middleware,这样对于无 index file 的目录,我们可以看到目录文件列表。

单一站点

1
2
3
4
5
localhost:8080

gzip                # 支持 gzip 压缩
root /home/mes/www  # 网站目录
...                 

多站点部署

Note: 多站点部署即是: 80 端口多路复用

如果需要配置独立的虚拟主机,需要将配置信息移动到站点名之后的大括号内:

1
2
3
4
5
6
7
8
9
mysite.com {
    root /www/mysite.com
}

sub.mysite.com {
    root /www/sub.mysite.com
    gzip
    log ../access.log
}

Note:

  • 左括号必须与站点名位于同一行,而右括号则是必须单起一行
  • 站点地址配置多个的话,需要用 , 空格 隔开, 且最后的地址和大括号之间也要有空格
1
2
3
localhost:2020, https://site.com, http://mysite.com {
    ...
}

当 Caddy 检测到站点名符合下列条件时会自动使用 Let’s Encrypt 脚本来为站点添加 HTTPS 支持,并且自动监听 80 与 443 端口:

  • 主机名不可为空并且没有 localhost 与 IP 地址

  • 端口号未明确指定为 80

  • Scheme 未明确指定为 http

  • TLS 未被关闭

  • 未指明证书

返回目录

反向代理

proxy 指令提供了基本的反向代理功能, 其支持 Health Checks 和 Failovers, 并且支持对 Websocket 的反向代理。

  • 其基本语法为:proxy from to

    • from: 即是请求匹配的基本路径
    • to: 则是请求转发的端点地址。
  • 将所有发往 /v0 的API接口请求转发到 localhost:7005 的后端服务程序

1
proxy /v0 localhost:7005
  • 使用随机策略将所有请求负载均衡到三个后端服务器
1
proxy / web1.local:7005 web2.local:8005 web3.local:8007
  • 使用循环机制
1
2
3
proxy / web1.local:80 web2.local:90 web3.local:100 {    
    policy round_robin
}
  • 添加健康检查,并且透明转发主机名、地址与上游:
1
2
3
4
5
proxy / web1.local:80 web2.local:90 web3.local:100 {    
    policy round_robin
    health_check /health
    transparent
}
  • 转发 websocket 请求
1
2
3
proxy /ws localhost:7005 {
    websocket
}
  • 避免对静态请求转发
1
2
3
proxy / localhost:7005 {
    except /static/ /robots.txt
}

Example:

1
2
3
4
5
6
localhost:2015 {
    log ./2015.log

    proxy /foo localhost:9001
    proxy /bar localhost:9002
}
  • 当访问 localhost:2015/foo 时,实际上访问的是 9001 端口的服务程序;
  • 当访问 localhost:2015/bar 时,实际上访问的是 9002 端口的服务程序。
  • 使用 transparent 指令增加 X-* 的头

    1
    2
    3
    4
    
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Proto {scheme}

服务器IP 反向代理

用服务器的 IP 来反向代理一个 http 协议的网站 http://www.baidu.com

1
2
3
4
:80 {
    gzip
    proxy / http://www.baidu.com
}

Note: 服务器IP 也可以反向代理 HTTPS 协议的网站,但是需要自签SSL证书,现在的浏览器一般都不会认 自签的SSL证书,所以不建议这么做

域名 反向代理 HTTP

用域名来反向代理一个 http 协议的网站 http://www.baidu.com

1
2
3
4
http://toyoo.ml {
    gzip
    proxy / http://www.baidu.com
}

域名 反向代理 HTTPS

1
2
3
4
5
https://toyoo.ml {
    gzip
    tls /path/to/xxx.crt /path/to/xxx.key
    proxy / https://www.baidu.com
}

HTTP 重定向为 HTTPS

当我们手动指定 SSL 证书和密匙来配置的话,Caddy 只会监听 443 端口(https),并不会自动设置 80 端口(http)的重定向(如果是Caddy自动申请的SSL证书,那么就自动做好了),如果要做重定向的话,可以这样做:

1
2
3
4
5
6
7
8
9
http://toyoo.ml, http://233.toyoo.ml, https://666.toyoo.ml {
    redir https://toyoo.ml{url}
}

https://toyoo.ml {
    gzip
    tls /path/to/xxx.crt /path/to/xxx.key
    proxy / https://www.baidu.com
}

负载均衡

Caddy支持负载均衡配置,并支持三种负载均衡算法:random(随机)、least_conn(最少连接)以及 round_robin (轮询调度); 负载均衡同样是通过 proxy middleware 实现的.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
localhost:2015 {
    log ./2015.log

    proxy / localhost:9001 localhost:9003 {
        policy round_robin
    }
    proxy /bar localhost:9002 localhost:9004 {
        policy least_conn
    }
}

返回目录

Websocket

Caddy 内建支持 websocket 连接, 其允许客户端发起 WebSocket 连接的时候服务端执行某个简单的指令,其基本语法如下:

1
websocket [path] command

Caddyfile 配置如下:

1
websocket /echo "echo "hello world""

HTTPS

我们只需要提供一个邮箱账号, Caddy 即可使用 tls 指令可为网站开启 https 功能, 并自动申请、配置和续约SSL证书, 其命令格式如下:

1
tls your@emial.com

或者指定已有证书和私钥的路径, 这样的话 caddy 就不会去自动申请证书,而是使用路径给出的证书了。

1
tls /path/to/cert.pem /path/to/key.pem

Note:

  • cert: 指定CA的根证书
  • key: 指定CA的私有密钥
  • 需要在浏览器导入CA跟证书

自助申请letsencrypt证书

1
2
3
4
5
https://domain.com {
    gzip
    tls your@email.com
    proxy /api/v0 localhost:7005
}

Note: 申请 SSL证书前,请务必提前解析好域名记录(解析后最好等一会,以全球生效),否则 Caddy会申请并配置失败! - Caddy自动申请SSL证书位置:/.caddy/acme/acme-v01.api.letsencrypt.org/sites/xxx.xxx(域名)/

自签发证书

在本地开发时,自然没法用 Let’s Encrypt 来签证书,这时候可以用 tls 指令自签发证书; 但是,客户端是不认自签发的证书的,需要手动信任。

1
2
3
4
5
https://domain.com {
    gzip
    tls /path/to/cert.pem /path/to/key.pem
    proxy /api/v0 localhost:7005
}

Note: 启动 Caddy 时,Caddy 会自动在内存里创建证书。由于证书是存在内存里的,所以下次启动的时候证书又会重新生成,需要再次手动信任。

返回目录

权限认证

Basic Auth

JWT

用 CORS 解决跨域

使用 cors 指令可为服务器添加跨域请求的能力:

1
2
3
4
5
6
7
8
9
cors /v0 {
    origin            http://allowedSite.com
    origin            http://anotherSite.org https://anotherSite.org
    methods           POST,PUT
    allow_credentials false
    max_age           3600
    allowed_headers   X-Custom-Header,X-Foobar
    exposed_headers   X-Something-Special,SomethingElse
}

Note: 在 allowed_headers & exposed_headers 等中,各个key之间只能用 , 隔开,且不能有其他的字符(例如:空格)等。

地址过滤

我们可以使用 ipfilter 指令来基于用户的 IP 来允许或者限制用户访问,其基本语法为:

1
2
3
4
5
6
7
8
ipfilter paths... {
    rule       block | allow
    ip         list or/and range of IPs...
    country    countries ISO codes...
    database   db_path
    blockpage  block_page
    strict
}
  • 仅允许某个IP访问
1
2
3
4
ipfilter / {
    rule allow
    ip 93.168.247.245
}

请求限流

我们可以使用 ratelimit 这个扩展指令来为资源添加请求限流的功能,对于单资源可以使用如下指令:

1
2
3
4
    ratelimit path rate burst unit 
    
    # 限制客户端每秒最多对 /storage/download/terminal.exe 资源发起两个请求,突发上线最多为 3 个
    ratelimit /storage/download/termianl.exe 2 3 second
  • 对多个资源的请求限流控制
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ratelimit rate burst unit {
    /assets/resource
    /download
    ...
}

# 限制对于资源文件的访问时长为 2 分钟
ratelimit 2 2 minute {
    /foo.html
    /dir
}

返回目录

重定向

Note: redir 默认使用指令 redir 可以完成请求跳转,语法格式为:

1
redir from to [code]
  • from: 请求地址(必须完全匹配,例如:/ 将匹配所有)

  • to: 重定向的目的地址 ( 这个也可以使用 占位符 )

  • code: is the HTTP status code to respond with; must be in the range [300-308] excluding 306. May also be meta to issue meta tag redirect for browsers. The default status code is 301 Moved Permanently.

Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
http://bitbucket.robot-qixing.com {
	redir http://192.168.1.8:7990{uri}
}

http://jira.robot-qixing.com {
	redir http://192.168.1.8:8088{uri}
}

http://confluence.robot-qixing.com {
	redir http://192.168.1.8:7999{uri}
}

生产环境使用

生产环境使用Caddy配置文件一般放置在:/etc/caddy 目录下, 且不要使用 root 账号去运行 caddy

Instructions

  • run caddy as user www-data and group www-data, with UID and GID 33

Caddy 配置

修改 caddy 可执行文件使用权限

1
2
3
sudo cp /path/to/caddy /usr/local/bin
sudo chown root:root /usr/local/bin/caddy
sudo chmod 755 /usr/local/bin/caddy

Give the caddy binary the ability to bind to privileged ports (e.g. 80, 443) as a non-root user:

1
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy

创建用户组(www-data)及用户(www-data)

1
2
3
4
5
6
sudo groupadd -g 33 www-data
sudo useradd \
  -g www-data --no-user-group \
  --home-dir /var/www --no-create-home \
  --shell /usr/sbin/nologin \
  --system --uid 33 www-data

Note: 可能出现错误:useradd: UID 33 is not unique,这里换成 333 重新执行即可(问题原因还未查明验证)

创建存放 caddy 配置文件的目录

1
2
sudo mkdir /etc/caddy
sudo chown -R root:www-data /etc/caddy

创建 SSL 证书存放目录

1
2
3
sudo mkdir -p /etc/ssl/caddy
sudo touch www-data:root /etc/ssl/caddy
sudo chmod 0770 /etc/ssl/caddy 

Note: 因为 ssl 文件夹里存放私钥,所以权限设置成 0770 禁止其他用户访问

创建 Caddyfile

1
2
3
sudo cp /path/to/Caddyfile /etc/caddy/
sudo chown www-data:www-data /etc/caddy/Caddyfile
sudo chmod 444 /etc/caddy/Caddyfile

Note: 这里 Caddyfile 权限在 root(我当前登录用户) 时是 read-only, 所以需要注意修改该文件时要赋予它可写的权限

最后,创建一个网址放置目录, 并且将需要部署的网站 (例如:qs.com ) 拷贝到 www 目录下

1
2
3
sudo mkdir -p /var/www
sudo chown www-data:www-data /var/www
sudo chmod 555 /var/www
1
2
3
sudo cp -R qs.com /var/www/
sudo chown -R www-data:www-data /var/www/qs.com
sudo chmod -R 555 /var/www/qs.com

Noet: 部署站点时需要在Caddyfile中用指令: root /var/www/qs.com 指定网站根目录, example:

1
2
3
4
domain.com {
    root /var/www/qx.com
    ...
}

系统服务(Linux)

README

创建 systemd service

1
2
3
sudo cp caddy.service /etc/systemd/system/
sudo chown root:root /etc/systemd/system/caddy.service
sudo chmod 644 /etc/systemd/system/caddy.service

caddy.service 内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[Unit]
Description=Caddy HTTP/2 web server
After=syslog.target
After=network.target

[Service]
User=www-data
Group=www-data
LimitNOFILE=64000
ExecStart=/usr/local/bin/caddy --conf=/etc/caddy/Caddyfile
Restart=on-failure

[Install]
WantedBy=multi-user.target

启动服务

1
2
3
sudo systemctl daemon-reload
sudo systemctl start caddy.service
sudo systemctl status caddy.service

See Also

Thanks to the authors 🙂