Caddy 是一個 Go 編寫的 Web 服務(wù)器,類似于 Nginx

Caddy 是一個 Go 編寫的 Web 服務(wù)器,類似于 Nginx

Caddy 是一個 Go 編寫的 Web 服務(wù)器,類似于 Nginx,Caddy 提供了更加強大的功能,隨著 v2 版本發(fā)布 Caddy 已經(jīng)可以作為中小型站點 Web 服務(wù)器的另一個選擇;相較于 Nginx 來說使用 Caddy 的優(yōu)勢如下:


自動的 HTTPS 證書申請(ACME HTTP/DNS 挑戰(zhàn))


自動證書續(xù)期以及 OCSP stapling 等


更高的安全性包括但不限于 TLS 配置以及內(nèi)存安全等


友好且強大的配置文件支持


支持 API 動態(tài)調(diào)整配置(有木有人可以搞個 Dashboard)


支持 HTTP3(QUIC)


支持動態(tài)后端,例如連接 Consul、作為 k8s ingress 等


后端多種負載策略以及健康檢測等


本身 Go 編寫,高度模塊化的系統(tǒng)方便擴展(CoreDNS 基于 Caddy1 開發(fā))


……


就目前來說,Caddy 對于我個人印象唯一的缺點就是性能沒有 Nginx 高,但是這是個仁者見仁智者見智的問題;相較于提供的這些便利性,在性能可接受的情況下完全有理由切換到 Caddy。


編譯 Caddy2


注意: 在 Caddy1 時代,Caddy 官方發(fā)布的預(yù)編譯二進制文件是不允許進行商業(yè)使用的,Caddy2 以后已經(jīng)全部切換到 Apache 2.0 License,具體請參考 issue#2786。


在默認情況下 Caddy2 官方提供了預(yù)編譯的二進制文件,以及自定義 build 下載頁面,不過對于需要集成一些第三方插件時,我們?nèi)孕璨捎霉俜教峁┑?xcaddy 來進行自行編譯;以下為具體的編譯過程:

1.1、Golang 環(huán)境安裝


本部分編譯環(huán)境默認為 Ubuntu 20.04 系統(tǒng),同時使用 root 用戶,其他環(huán)境請自行調(diào)整相關(guān)目錄以及配置;編譯時自行處理好科學(xué)上網(wǎng)相關(guān)配置,也可以直接用國外 VPS 服務(wù)器編譯。


首先下載 go 語言的 SDK 壓縮包,其他平臺可以從 https://golang.org/dl/ 下載對應(yīng)的壓縮包:


wget https://golang.org/dl/go1.15.6.linux-amd64.tar.gz

Caddy 是一個 Go 編寫的 Web 服務(wù)器,類似于 Nginx

下載完成后解壓并配置相關(guān)變量:


# 解壓


tar -zxvf go1.15.6.linux-amd64.tar.gz


# 移動到任意目錄


mkdir -p /opt/devtools


mv go /opt/devtools/go


# 創(chuàng)建 go 相關(guān)目錄


mkdir -p ${HOME}/gopath/{src,bin,pkg}


# 調(diào)整變量配置,將以下變量加入到 shell 初始化配置中


# bash 用戶請編輯 ~/.bashrc


# zsh 用戶請編輯 ~/.zshrc


exportGOROOT= '/opt/devtools/go'


exportGOPATH= " ${HOME}/gopath"


exportGOPROXY= 'https://goproxy.cn'# 如果已經(jīng)解決了科學(xué)上網(wǎng)問題,GOPROXY 變量可以刪除,否則可能會起反作用


exportPATH= " ${GOROOT}/bin: ${GOPATH}/bin: ${PATH}"


# 讓配置生效


# bash 用戶替換成 ~/.basrc


# 重新退出登錄也可以


source~/.zshrc


配置完成后,應(yīng)該在命令行執(zhí)行 go version 并有以下成功返回:


bleem ? ~ go version


go version go1.15.6 linux/amd64


1.2、安裝 xcaddy


按照官方文檔直接命令行執(zhí)行 go get -u github.com/caddyserver/xcaddy/cmd/xcaddy 安裝即可:


bleem ? ~ go get -u github.com/caddyserver/xcaddy/cmd/xcaddy


go: downloading github.com/caddyserver/xcaddy v0.1.7


go: found github.com/caddyserver/xcaddy/cmd/xcaddy ingithub.com/caddyserver/xcaddy v0.1.7


go: downloading github.com/Masterminds/semver/v3 v3.1.0


go: github.com/Masterminds/semver/v3 upgrade => v3.1.1


go: downloading github.com/Masterminds/semver/v3 v3.1.1


.....


安裝完成后應(yīng)當(dāng)在命令行可以直接執(zhí)行 xcaddy 命令:


# xcaddy 并沒有提供完善的命令行支持,所以 `--help` 報錯很正常


bleem ? ~ xcaddy -- help


go: cannot match "all": working directory is not part of a module


2021/01/07 12:15:56 [ERROR] exec[go list -m -f={{if .Replace}}{{.Path}} => {{.Replace}}{{end}} all]: exitstatus 1:


1.3、編譯 Caddy2


編譯之前系統(tǒng)需要安裝 jq 、 curl 、 git 命令,沒有的請使用 apt install -y curl git jq 命令安裝;


自行編譯的目的是增加第三方插件方便使用,其中官方列出的插件可以從 Download 頁面獲取到:




其他插件可以從 GitHub 上尋找或者自行編寫,整理好這些插件列表以后只需要使用 xcaddy 編譯即可:


# 獲取最新版本號,其實直接去 GitHub realse 頁復(fù)制一下就行


# 這里轉(zhuǎn)化為腳本是為了方便自動化


exportversion=$(curl -s "https://api.github.com/repos/caddyserver/caddy/releases/latest"| jq -r .tag_name)


# 使用 xcaddy 編譯


xcaddy build ${version}--output ./caddy_ ${version}


--with github.com/abiosoft/caddy-exec


--with github.com/caddy-dns/cloudflare


--with github.com/caddy-dns/dnspod


--with github.com/caddy-dns/duckdns


--with github.com/caddy-dns/gandi


--with github.com/caddy-dns/route53


--with github.com/greenpau/caddy-auth-jwt


--with github.com/greenpau/caddy-auth-portal


--with github.com/greenpau/caddy-trace


--with github.com/hairyhenderson/caddy-teapot-module


--with github.com/kirsch33/realip


--with github.com/porech/caddy-maxmind-geolocation


--with github.com/caddyserver/format-encoder


--with github.com/mholt/caddy-webdav


編譯過程日志如下所示,稍等片刻后將會生成編譯好的二進制文件:




編譯成功后可以通過 list-modules 子命令查看被添加的插件是否成功編譯到了 caddy 中:


bleem ? ~ ./caddy_v2.3.0 list-modules


admin.api.load


admin.api.metrics


caddy.adapters.caddyfile


caddy.listeners.tls


caddy.logging.encoders.console


caddy.logging.encoders.filter


caddy.logging.encoders.filter.delete


caddy.logging.encoders.filter.ip_mask


caddy.logging.encoders.formatted


caddy.logging.encoders.json


caddy.logging.encoders.logfmt


caddy.logging.encoders.single_field


caddy.logging.writers.discard


caddy.logging.writers.file


caddy.logging.writers.net


caddy.logging.writers.stderr


caddy.logging.writers.stdout


caddy.storage.file_system


dns.providers.cloudflare


dns.providers.dnspod


dns.providers.duckdns


dns.providers.gandi


dns.providers.route53


exec


http


http.authentication.hashes.bcrypt


http.authentication.hashes.scrypt


http.authentication.providers.http_basic


http.authentication.providers.jwt


......


安裝 Caddy22.1、宿主機安裝


宿主機安裝 Caddy2 需要使用 systemd 進行守護,幸運的是 Caddy2 官方提供了各種平臺的安裝包以及 systemd 配置文件倉庫;目前推薦的方式是直接采用包管理器安裝標(biāo)準(zhǔn)版本的 Caddy2,然后替換自編譯的可執(zhí)行文件:


# 安裝標(biāo)準(zhǔn)版本 Caddy2


sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https


curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/gpg/gpg.155B6D79CA56EA34.key'| sudo apt-key add -


curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/cfg/setup/config.deb.txt?distro=debian&version=any-version'| sudo tee -a /etc/apt/sources.list.d/caddy-stable.list


sudo apt update


sudo apt install caddy


# 替換二進制文件


systemctl stop caddy


rm -f /usr/bin/caddy


mv ./caddy_v2.3.0 /usr/bin/caddy


2.2、Docker 安裝


Docker 用戶可以通過 Dockerfile 自行編譯 image,目前我編寫了一個基于 xcaddy 的 Dockerfile,如果有其他插件需要集成自行修改重新編譯即可;當(dāng)前 Dockerfile 預(yù)編譯的鏡像已經(jīng)推送到了 Docker Hub 中,鏡像名稱為 mritd/caddy 。


配置 Caddy2


Caddy2 的配置文件核心采用 json,但是 json 可讀性不強,所以官方維護了一個轉(zhuǎn)換器,抽象出稱之為 Caddyfile 的新配置格式;關(guān)于 Caddyfile 的完整語法請查看官方文檔 https://caddyserver.com/docs/caddyfile,本文僅做一些基本使用的樣例。


3.1、配置片段


Caddyfile 支持類似代碼中 function 一樣的配置片段,這些配置片段可以在任意位置被 import ,同時可以接受參數(shù),以下為配置片斷示例:


# 括號內(nèi)為片段名稱,可以自行定義


(TLS) {


protocols tls1.2 tls1.3


ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256


}


# 在任意位置可以引用此片段從而達到配置復(fù)用


import TLS


3.2、配置模塊化


import 指令除了支持引用配置片段以外,還支持引用外部文件,同時支持通配符,有了這個命令以后我們就可以方便的將配置文件進行模塊化處理:


# 引用外部的 /etc/caddy/*.caddy


import /etc/caddy/*.caddy


3.3、站點配置


針對于站點域名配置,Caddyfile 比較自由化,其格式如下:


地址 {


站點配置


}


關(guān)于這個 “地址” 接受多種格式,以下都為合法的地址格式:


localhost


example.com


:443


http://example.com


localhost:8080


127.0.0.1


[::1]:2015


example.com/foo/*


*.example.com


http://


3.4、環(huán)境變量

Caddyfile 支持直接引用系統(tǒng)環(huán)境變量,通過此功能可以將一些敏感信息從配置文件中剔除:


# 引用環(huán)境變量 GANDI_API_TOKEN


dns gandi { $GANDI_API_TOKEN}


3.5、配置片段參數(shù)支持


針對于配置片段,Caddyfile 還支持類似于函數(shù)代碼的參數(shù)支持,通過參數(shù)支持可以讓外部引用時動態(tài)修改配置信息:


(LOG) {


log{


format json {


time_format "iso8601"


}


# "{args.0}" 引用傳入的第一個參數(shù),此處用于動態(tài)傳入日志文件名稱


output file "{args.0}"{


roll_size 100mb


roll_keep 3


roll_keep_for 7d


}


}


}


# 引用片段


import LOG "/data/logs/mritd.com.log"