- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Caddy 一个用Go实现的Web Server由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
这是一个Web Server的时代,apache2与nginx共舞,在追求极致性能的路上,没有最高,只有更高。但这又是一个追求个性化的时代,有些Web Server并没有去挤“Performance提升”这一独木桥,而是有着自己的定位,Caddy就是这样一个开源Web Server.
Caddy的作者Matt Holt在caddy官网以及FAQ中对caddy的目标阐释如下: 其他Web Server为Web而设计,Caddy为human设计。功能定位上,与经常充当最前端反向代理的nginx不同,caddy致力于成为一个易用的静态 文件Web Server。可以看出Caddy主打易用性,使用配置简单。并且得益于Go的跨平台特性,caddy很容易的支持了三大主流平台:Windows、 Linux、Mac。在Caddy开发者文档中,我们可以看到caddy还可以在Android(linux arm)上运行。caddy目前版本为0.7.1,还不稳定,且后续版本可能变化较大,甚至与前期版本不兼容,因此作者目前不推荐caddy在生产环境被 重度使用.
关注caddy,是因为caddy填补了go在通用web server这块的空白(也许有其他,但我还不知道),同时Web server in go也“响应”了近期Golang去C化的趋势(Go 1.5中C is gone!),即便caddy作者提到caddy的目标并非如nginx那样。但未来谁知道呢?一旦Go性能足够高时,一旦caddy足够稳定时,自然而 然的就会有人将其用在某些应用的生产环境中替代nginx或apache2了。一套全Go的系统,在部署、运维方面也是有优势的.
1、安装和运行caddy 。
和诸多go应用一样,我们可以直接从caddy的github.com releases页中找到最新发布版(目前是0.7.1)的二进制包。这里使用的是caddy_darwin_amd64.zip.
下载解压后,进入目录,直接执行./caddy即可将caddy运行起来.
$caddy 0.0.0.0:2015 。
在浏览器里访问localhost:2015,页面上没有预期显示的类似"caddy works!”之类的默认Welcome页面,而是“404 Not Found"。虽然这说明caddy已经work了,但没有一个default welcome page毕竟对于caddy beginer来说并不友好。这里已经向作者提了一个sugguestion issue.
2、caddy原理 。
Go的net/http标准库已经提供了http server的实现,大多数场合这个http server都能满足你的需要,无论是功能还是性能。Caddy实质上也是一个Go web app,它也import net/http,嵌入*http.Server,并通过handler的ServeHTTP方法为每个请求提供服务。caddy使用 http.FileServer作为处理 静态文件的基础。caddy的诱人之处在于其middleware,将诸多middleware串成一个middleware chain以提供了灵活的web服务。另外caddy中的middleware还可以独立于caddy之外使用.
caddy从当前目录的Caddyfile(默认)文件中读取配置,当然你也可以通过-conf指定配置文件路径。Caddyfile的配置格式 的确非常easy,这也符合caddy的目标.
Caddyfile总是以站点的Addr开始的.
单一站点的Caddyfile样例如下:
1
2
3
4
|
//Caddyfile
localhost:2015
gzip
log ./2015.log
|
Caddy也支持配置多个站点,类似virtualhost的 配置(80端口多路复用):
1
2
3
4
5
6
7
8
9
10
|
//Caddyfile
foo.com:80 {
log ./foo.log
gzip
}
bar.com:80 {
log ./bar.log
gzip
}
|
为了实现风格上的统一,单一站点也最好配置为如下这种格式(代码内部称之为 Server Block):
1
2
3
4
|
localhost:2015 {
gzip
log ./2015.log
}
|
这样Caddyfile的配置文件模板样式类似于下面这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
host1:port {
middleware1
middleware2 {
… …
}
… …
}
host2:port {
middleware1
middleware2 {
… …
}
… …
}
… …
|
关于middleware,在caddy文档中有较为详细的说明和例子。对于caddy这样一个年轻的开源项目而言,其文档还算是相对较全的,虽 然现在还不能和nginx、 apache比.
caddy中的middleware就是一个实现了middleware.Handler接口的struct,例如gzip这个 middleware
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// middleware.go
type Middleware func(Handler) Handler
type Handler interface {
ServeHTTP(http.ResponseWriter, *http.Request) (int, error)
}
// gzip/gzip.go
type Gzip struct {
Next middleware.Handler
}
func (g Gzip) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
return g.Next.ServeHTTP(w, r)
}
…. …
gz := gzipResponseWriter{Writer: gzipWriter, ResponseWriter: w}
// Any response in forward middleware will now be compressed
status, err := g.Next.ServeHTTP(gz, r)
… …
}
|
middleware.Handler的函数原型与http.Handler的不同,不能直接作为http.Server的Handler使用。caddy使用了下面这个idiomatic go pattern
type appHandler func(http.ResponseWriter, *http.Request) (int, error) 。
1
2
3
4
5
|
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if status, err := fn(w, r); err != nil {
http.Error(w, err.Error(), status)
}
}
|
当然这个pattern有很多变种,但思路大致类似。一个middleware chain大致就是handler1(handler2(handler3))的调用传递.
前面说过caddy是基于http.FileServer的静态文件Web Server,FileServer总会作为middleware chain的最后一环,如果没有配置任何middleware,那你的server就是一个静态文件server.
3、caddy典型应用 。
【静态文件Server】 。
caddy的最基础应用实际就是一个静态文件Server,底层由http.FileServer承载,当然caddy封装了http.FileServer,做了一些拦截处理,最后将w, r传递给http.ServeContent去处理文件数据.
第一次执行./caddy,实际上就启动了一个静态文件Server。但这个server不默认支持你navigate directory。如果你知道website root目录(如果没有指定root,则caddy执行的当前路径会作为website的root路径)下的文件名,比如foo.txt,你可以在浏览器 中输入:localhost:2015/foo.txt,caddy会执行正确的服务,浏览器也会显示foo.txt的全文.
对于静态文件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
|
localhost:2015 {
browse
}
|
【反向代理】 。
caddy支持基本的反向代理功能。反向代理配置通过proxy middleware实现.
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端口的服务程序.
【负载均衡】 。
Caddy支持负载均衡配置,并支持三种负载均衡算法:random(随机)、least_conn(最少连接)以及round_robin(轮询调度).
负载均衡同样是通过proxy middleware实现的.
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
}
}
|
【支持fastcgi代理】 。
caddy同样支持fastcgi代理,可以将请求通过fastcgi接口发送给后端的实现fastcgi的server。我们以一个"hello world"的php server为例.
mac os上自带了php-fpm,一个实现了fastcgi的php cgi进程管理器。caddy将请求转发给php-fpm监听的端口,后者会启动php-cgi解释器,解释index.php,并将结果返回给caddy.
mac os上的php-fpm默认没有随机启动。我们需要简单配置一下:
$mkdir phptest $mkdir -p phptest/etc $mkdir -p phptest/log $cd phptest $sudo cp /private/etc/php-fpm.conf.default ./etc $cd ./etc $sudo chown tony php-fpm.conf.default $mv php-fpm.conf.default php-fpm.conf 。
编辑php-fpm.conf,保证下面两项是非注释状态的:
error_log = log/php-fpm.log listen = 127.0.0.1:9000 。
我们通过network socket进行fastcgi通信.
回到phptest目录下,执行
php-fpm -p ~/test/go/caddy/phptest 。
执行后,php-fpm就会转入后台执行了.
接下来我们来配置Caddyfile:
1
2
3
4
|
localhost:2015 {
fastcgi / 127.0.0.1:9000 php
log ./2015.log
}
|
这里配置的含义是:将全部请求转发到9000端口,这里的php是一个preset(预配置集合),相当于:
1
2
3
|
ext .php
split .php
index index.php
|
我们在phptest目录下创建一个index.php文件,内容如下:
<?php echo "Hello World\n"; ?> 。
好了,现在启动caddy,并使用浏览器访问localhost:2015试试。你会看到"Hello World"呈现在浏览器中.
【git push发布】 。
对于一些静态站点,caddy支持git directive,实现在server启动以及运行时定期git pull你的项目库,将最新更新pull到server上.
caddy文档中给出两个例子:
第一个是一个php站点,定期pull项目库,实现server更新:
1
2
3
4
|
git git@github.com:user/myphpsite {
key /home/user/.ssh/id_rsa
}
fastcgi / 127.0.0.1:9000 php
|
第二个是一个hugo支撑的静态站点,每次pull后,执行hugo命令生成新的静态页面:
1
2
3
4
|
git github.com/user/site {
path ../
then hugo –destination=/home/user/hugosite/public
}
|
注意:git directive并非middleware,而是一个单独的goroutine实现的.
4、小结 。
caddy的功能不局限于上面的几个例子,上面只是几个最为常见的场景而已。caddy目前还很年轻,应用不多,但知名golang网站 gopheracademy.com(GopherCon组织方)是由Caddy support的。caddy还在积极进化,有兴趣的Gopher可持续关注.
最后此篇关于Caddy 一个用Go实现的Web Server的文章就讲到这里了,如果你想了解更多关于Caddy 一个用Go实现的Web Server的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
本周我将在 Windows Server 2008 上设置一个专用的 SQL Server 2005 机器,并希望将其精简为尽可能简单,同时仍能发挥全部功能。 为此,“服务器核心”选项听起来很有吸引力
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 已关闭 8 年前。 Improve
我获取了 2014 版本数据库的备份,并尝试在另一台服务器中将其恢复到具有相同名称和登录名的数据库中。此 SQL Server 版本是 2016。 恢复备份文件时,出现此错误: TITLE: Micr
我获取了 2014 版本数据库的备份,并尝试在另一台服务器中将其恢复到具有相同名称和登录名的数据库中。此 SQL Server 版本是 2016。 恢复备份文件时,出现此错误: TITLE: Micr
TFS 是否提供任何增强的方法来存储对 sql server 数据库所做的更改,而不是使用它来对在数据库上执行的 sql 语句的文本文件进行版本控制? 或者我正在寻找的功能是否仅在第 3 方工具(如
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 9 年前。 Improve this ques
我即将将我的 SQL Server 2012 实例升级到 SQL Server 2014。 我已经克隆了主机 Windows VM 并将其重命名为 foo-2012至 foo-2014 . 重新启动时
我想为 SQL Server 登录授予对数据库的访问权限。我知道 sp_grantdbaccess,但它已被弃用。我可以改用什么以及如何检查登录名是否还没有访问数据库的权限? 场景:UserA 创建数
客户别无选择,只能在接下来的几天内从 sql server 2000 迁移到 2008。测试显示 2005 年的重要功能出现了 Not Acceptable 性能下降,但 2008 年却没有。好消息是
我有一个测试数据库,我需要将其导出到我们客户的测试环境中。 这将是一次性的工作。 我正在使用 SQL Server 2005(我的测试数据库是 SQL Server 2005 Express) 执行此
我需要将一个 CSV 文件导入到 mongoDB 不幸的是我遇到了以下错误: error connecting to host: could not connect to server: se
我以为 R2 是一个补丁/服务包。我一直在寻找下载,但没有看到。因此,我假设 R2 是一个新版本,并且我需要 sqlserver 2008 r2 的安装介质来进行升级? 另外,我需要为新许可证付费吗?
我无法使用 SQL Server Management Studio 连接到 SQL Server。 我有一个连接字符串: 我尝试通过在服务器名中输入 myIP、在登录名中输入 MyID、在密码中
我们希望使用 SQL Server 加密来加密数据库中的几个列。我们还需要在生产和测试环境之间传输数据。看来最好的解决方案是在生产和测试服务器上使用相同的主 key 、证书和对称 key ,以便我可以
有没有可以分析 SQL Server 数据库潜在问题的工具? 例如: a foreign key column that is not indexed 没有 FILL FACTOR 的 uniquei
我正在尝试从我的 SQL 2012 BI 版本建立复制,但我收到一条奇怪的错误消息! "You cannot create a publication from server 'X' because
如果您使用 SQL Server 身份验证 (2005),登录详细信息是否以明文形式通过网络发送? 最佳答案 如您所愿,安全无忧... 您可以相当轻松地配置 SSL,如果您没有受信任的证书,如果您强制
我想将数据从一个表复制到不同服务器之间的另一个表。 如果是在同一服务器和不同的数据库中,我使用了以下 SELECT * INTO DB1..TBL1 FROM DB2..TBL1 (to copy w
我希望得到一些帮助,因为我在这个问题上已经被困了 2 天了! 场景:我可以从我的开发计算机(和其他同事)连接到 SERVER\INSTANCE,但无法从另一个 SQL Server 连接。我得到的错误
我正在尝试从我的 SQL 2012 BI 版本建立复制,但我收到一条奇怪的错误消息! "You cannot create a publication from server 'X' because
我是一名优秀的程序员,十分优秀!