無標題文檔

使用 Nginx 反向代理阿里云 OSS

上次将 Blog 的主机重新整理下了以后,这次抽空将站点的静态资源也整理了下。

虽然使用又拍云有一段时间了,也非常的稳定,但毕竟要「居安思危」,又拍云同时又提供了「融合云」的第三方存储的同步方案,于是就选择了阿里云的 OSS 作为存储的备份方案。

Aliyun OSS

上图是我目前的方案,客户端这边通过脚本或者其他工具上传到又拍云上,然后又拍云自动将增量数据同步到阿里云的 OSS,最后我再使用 Nginx 反向代理去访问两块同步的资源。

为什么使用反向代理,是因为由于「众所周知」的原因,在国内绑定 HTTP(S) 服务的域名是需要备案的,我觉得麻烦同时也不想浪费个域名做这样的事情。

同时使用反向代理的方式,后面自己还可以控制缓存、负载均衡等,可操作性更大一些。长话短说,在配置阿里云 OSS 的反向代理的时候碰到了些坑,在这里记录下。

首先,在阿里云 OSS 后台务必设置好权限,在 Bucket 中设置读写权限为「公共读」,以及在 Refer 设置为自己实际的情况(很重要)。

下面是目前的针对阿里云 OSS 的 Nginx 反向代理的具体配置,供参考:

location /<base_url>/ {
    proxy_pass http://<bucket>.oss-cn-shanghai.aliyuncs.com/;

    proxy_redirect off;
    proxy_set_header Host '<bucket>.oss-cn-shanghai.aliyuncs.com';
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header User-Agent $http_user_agent;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_cache_valid 200 302 3600m;

    proxy_buffer_size 256k;
    proxy_buffers 4 256k;
    proxy_read_timeout 600s;
    proxy_send_timeout 300s;
    proxy_temp_file_write_size 256k;

    expires max;
    etag off;
}

proxy_set_headerHost 必须要设定自己对应的主机名,例如我的阿里云 OSS 对应的主机在华东2(也就是上海机房)阿里云 OSS 是根据 Host 确定 Bucket 的名称的。顺便提一句,如果 Nginx 主机也是和 OSS 同个机房,那么可以使用内部 VPC 内网节省流量。

OSS Endpoint

由于反向代理的是静态资源,所以我考虑尽可能的多缓存时间以加快速度和减少请求流量,所以设置了 proxy_cache_valid 200 302 3600m 以及 expires max 强制缓存。

然后 reload Nginx 以后就可以看到效果了。由于目前 又拍云 和 阿里云 OSS 的内容是同步的,所以后面使用 Nginx 做负载均衡也是比较方便的事情,这里就不重复贴配置了。

顺便在这里吐槽下,个人不是很推荐买阿里云的香港服务器!因为又是那个「众所周知」的原因,阿里云的香港节点 HTTPS 流量是会被部分 ISP 给污染的

这块个人也是困扰了很久,然而不打算处理了,毕竟现在写 Blog 的人不多看 Blog 的人更少,被墙了反而能够更加自在些。

- EOF -

使用 Docker 部署 VPS 备忘

本 Blog 的代码也有很多的年头,当时使用的技术过了几年在目前看来有些的陈旧。同时,在 Vultr 的服务器空间也即将到期,所以考虑干脆做个迁移顺便将目前 VPS 上的服务也一起整理了下。

这一整理,发现了不少的巨坑,这在这里记录下。先说说在迁移前 VPS 目前的主要问题

  1. 部分代码老旧,同时又有新的代码,运行环境就有好几套;
  2. 尝试使用 Node 的工具进行开发,然而 Nginx 以及 php-fpm 独占了 80 端口,配置文件越来越复杂;
  3. 权限分配不合理,有部分的权限使用 root 运行有安全上的风险;
  4. 备份机制不合理,没有做到企业级的多点备份(虽然个人 VPS 没必要,但图个心安)。

其他情况不多说,重新整理以后的 VPS 应用架构图如下,相对来说还是不是很复杂:

https://gracecode.b0.upaiyun.com/2017_10_12/1507794332@800.png

综合价格以及习惯的因素(可能是情怀更多?),大部分选择了阿里云的服务。同时针对以上的问题,这边的解决方案是:

  1. 使用不同的 Docker 集群将 php5 和 php7 的应用分别调用,相互不受影响。老旧的代码就让它们在 php5 环境中「颐养天年」;
  2. 最前端使用 Tengine 分发请求到每个对应的 Docker,方便管理;
  3. 使用 Docker 以后,权限这块就相对来说好控制很多,宿主机不受任何的影响;
  4. 配置文件使用 git 管理起来,并托管到 Bitbucket,方便部署;
  5. 备份使用阿里云的 OSS 存档服务,价格很便宜而且也是安心很多。

同时,在这里汇总下碰到的几个坑和心得,供参考

  1. 官方 Docker 的 php7-fpm 是没有带 gd 库的,所以要自己 build 一个版本(生产环境顺便把 debug 这些都去掉);
  2. 因为只是在最外面 Router 应用服务使用 https,所以 PHP 应用内部需要增加判断下,防止判断失败,详见这里。简单的说,就是加个判断
/**
 *  Handle SSL reverse proxy
 *  @see https://www.variantweb.net/blog/wordpress-behind-an-nginx-ssl-reverse-proxy/
 */
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS']='on';
}

if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}
  1. Alpine Linux 的 apk 源有时候会不稳定,Docker build 的时候会有出错的几率,多重试就好。

--

补充下,有关 HTTPS 转发这块,khsing 提出了很好的建议,非常感谢:

刚才看了你的使用 Docker 那篇文,里面处理 WP 处理 https protocol
的方法还挺硬的,这事儿我之前在阿里云部署的适合也遇到了,不过我是在 nginx 上做了处理,这样就不用动 PHP 代码了。

map $http_x_forwarded_proto $forwarded_https { default off; https on; }
fastcgi_param HTTPS $forwarded_https;

-- eof --

自建基于 Linux 的 Time Capsule 服务

更改历史

前言

Apple 的 Time Machine 提供了非常完备的数据备份方案,但每次使用外接磁盘备份很 麻烦也很容易忘记备份。同时,个人对于 Time Capsule 「高昂的」售价(虽然它的确值那些钱)颇有微词。

其实,大部分管理员已经有数台 Linux 服务器,所以考虑能否安装类似 Time Capsule 的服务让 Linux 为 Mac 提供网络备份。

如果您和我一样有类似的需求,那么这篇文章可能就是你想要的 :^D

安装软件包

本人使用的 Linux 发行版为 Debian ,其他发行版的也应该类似。

首先,安装需要的软件包:

% sudo apt-get install netatalk
% sudo apt-get install avahi        # 通常这个包已经安装了的
% sudo apt-get install nss-mdns

注意:如果需要自己编译安装 netatalk 包,则需要加入 ssl 支持,具体看编译脚本参数。

配置

上面的软件包正常安装完毕以后,接下来就是配置了。

服务器端

1、编辑 /etc/default/netatalk 文件,找到对应的内容,更改为

ATALKD_RUN=yes
PAPD_RUN=no
CNID_METAD_RUN=yes
AFPD_RUN=yes
TIMELORD_RUN=no
A2BOOT_RUN=no

2、编辑文件 /etc/netatalk/afpd.conf 在最底部加入行:

- -tcp -noddp -uamlist uams_dhx.so,uams_dhx2.so -nosavepassword

3、编辑文件 /etc/nsswitch.conf 在最底部加入行:

hosts:  files mdns4_minimal [NOTFOUND=return] dns mdns4 mdns

4、新增文件 /etc/avahi/services/afpd.service,内容为:

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
    <name replace-wildcards="yes">%h</name>
    <service>
        <type>_afpovertcp._tcp</type>
        <port>548</port>
    </service>
    <service>
        <type>_device-info._tcp</type>
        <port>0</port>
        <txt-record>model=Xserve</txt-record>
    </service>
</service-group>

这个时候 netatalk 协议已经配置完毕,我们要共享出个目录让 Mac 映射为磁盘。编辑文 件 /etc/netatalk/AppleVolumes.default 加入下面的行:

~/TimeMachine   "TimeMachine"   allow:mingcheng    cnidscheme:cdb options:usedots,upriv,tm

简单得说明下:

Tips:由于备份数据比较大,可以考虑 mount --bind 映射到 Linux 本地的其他合适的分区或目录( 详细 )。

至此,基本的 Linux 服务器端配置完毕,重启服务(重启需要花点时间)

% service netatalk restart
% service avahi-daemon restart

https://gracecode.b0.upaiyun.com/2011_02_10/1297309091.png

https://gracecode.b0.upaiyun.com/2011_02_10/1297309108.png

重启服务以后,在 Mac 端连接 Linux 服务器,输入对应的用户名和密码以后,即可挂载已经配置好的磁盘。

Mac 端

在 Mac 端,我们还需要做些配置。打开终端(Terminal),执行下面的命令使 Time Machine 能够使用网络磁盘作为备份盘:

defaults write com.apple.systempreferences TMShowUnsupportedNetworkVolumes 1

由于部分兼容性问题,还需要另外手工制作磁盘疏散镜像。打开「偏好设置」中的「共享」,可以看见「电脑名称」, 例如我的是「明城的 Macbook Pro」(注意大小写和空格),这里将其命名为 <computer_name>

https://gracecode.b0.upaiyun.com/2011_02_10/1297309156.png

然后,打开终端粘贴如下面的命令获得本机的网卡 Mac 地址,这里将其命名为 <mac address>

ifconfig en0 | grep ether | awk '{print $2}' | sed 's/://g'

如图,例如我的是

https://gracecode.b0.upaiyun.com/2011_02_10/1297309174.png

然后运行下面的命令,注意将上步骤获得的 <computer_name><mac address> 代入命令行:

sudo hdiutil create -size 320g -type SPARSEBUNDLE -nospotlight -volname "Backup of <computer_name>" \
    -fs "Case-sensitive Journaled HFS+" -verbose ~/Desktop/<computer_name>_<mac address>.sparsebundle

注意:-size 320g 参数是本机的硬盘容量,请根据实际情况更改。

最终在桌面会有个类似我本机的文件名(注意空格等字符):

明城的 Macbook Pro_0026bb6a1f40.sparsebundle

然后将这文件扔到上面配置好的 Linux 网络磁盘根目录。打开 TimeMachine 选择对应的磁 盘,即可以开始开始备份。

https://gracecode.b0.upaiyun.com/2011_02_10/1297309244.png

https://gracecode.b0.upaiyun.com/2011_02_10/1297309278.jpg

Tips:首次网络备份会比较缓慢,建议插入网线。

一般问题

问:这样做符不符合 Apple 的协议?

答:未知,如有明确结果的,请各位告知。

https://gracecode.b0.upaiyun.com/2011_02_10/1297309298.jpg

问:为什么我选择网络磁盘以后,TimeMachine 一直在「正在准备磁盘」?

答:这是磁盘疏散镜像没有制作正确,或者你命名的文件名不正确。可以暂停备份,挂载网络磁盘看 TimeMachine 为你自己生成的文件名,然后在将上面步骤生成的文件替换。

问:TimeMachine 的备份数据是加密过的吗?

答:抱歉,保存在服务器上的数据是 没有加密 的(数据传输如有 SSL 是加密的)。

参考资源

-- EOF --

nginx_concat_module 安装和配置

简介

nginx_concat_module淘宝研发的针对 nginx 的文件合并模块 ,主要用于 合并前端代码减少 http 请求数 。如果你的应用环境中部署了 nginx,那么可以考虑尝试此模块减少请求数。

安装

安装 nginx_concat_module 需要重新编译 nginx。 可以从这里 checkout 最新的代码

svn checkout http://code.taobao.org/svn/nginx_concat_module/trunk/ $NGINX_CONCAT_MODULE

然后下载适合你自己版本的 nginx 源码包 ,在 ./configure 中增加参数

--add-module=$NGINX_CONCAT_MODULE

就可以继续 nginx 的编译安装过程。

Tips

顺便废话下,默认编译 nginx 的 gcc 参数带了 「-g」 开关。处于洁癖和性能考虑,可以考虑将其关闭。编辑文件

$NGINX_SOURCE_DIR/auto/cc/gcc

注释掉下面的行

CFLAGS="$CFLAGS -g"

如果觉得有必要,可以修改下面的编译参数(感觉性能提高不大)

NGX_GCC_OPT="-O2"

配置

新的 nginx 编译安装好以后,配置 nginx_concat_module 主要有如下的选项

# nginx_concat_module 主开关
concat on;

# 最大合并文件数
# concat_max_files 10;

# 只允许同类型文件合并
# concat_unique on;

# 允许合并的文件类型,多个以逗号分隔。如:application/x-javascript, text/css
# concat_types text/html;

(详细察看安装包下 INSTALL 和 README 文件)。其实不用那么复杂,简单的配置

location / {
     concat    on;
}

就可以合并 javascript、css 等文件了(顺便注意是否和 rewrite 规则冲突)。

使用

https://gracecode.b0.upaiyun.com/2010_12_22/1293011346.png

上面的图可以说明如何使用 nginx_concat_module 。随着以后的深度使用, 如果感觉 url 过长, 那么就要考虑另一种优化了

ps,再罗嗦句,有关 nginx_concat_module 性能方面的忧虑,我想应该可以让人放心,尤其是看了淘宝首页的源代码以后 :^)

有关 nginx_concat_module 的任何意见和建议,可以联系其作者 Joshua Zhu <shudu[at]taobao.com>

-- EOF --

因闰秒造成的误差

项目中碰到 PHP 和数据库之间,计算存在时间计算误差。大致的情况为根据段时间字符串,例如

2012-12-14 00:00:00 UTC

使用 MySQL 的 UNIX_TIMESTAMP 函数以及 PHP 的 strtotime 计算得出的时间戳,大概有半分钟(差不多有28秒)的误差。

同时,比较‘诡异’的是直接使用当前时间(MySQL 中 UNIX_TIMESTAMP 不带参数,同时 PHP 直接使用 time 函数),却不存在误差( 测试脚本 )。

排除了 PHP 和 MySQL 之间因为时区设置造成的时间误差 -- 根据经验,如果是时区设置造成的时间误差,应该有几个小时不会那么少。

搜索解决问题期间扫了下 这篇帖子 ,觉得应该是 ‘闰秒’ 这玩意造成的问题。搜索 PHP 闰秒相关的配置似乎没有相关的, 不过在这里似乎找到了些答案

You also can experience this behavior if your system timezone
is with leap seconds. To avoid the problem in this case please
run query UPDATE mysql.time_zone SET Use_leap_seconds='N' 
and restart the server. Please inform us if this helps.

按照上述的步骤执行,解决了问题。

回过头来,我在工作机(Windows)上测试,发现并不起作用。研究了下, 原来闰秒也需要操作系统的支持

1、对于大多数新的 Linux 内核,在设计时它们都是支持闰
   秒的,这一点在 REHL4/5 的 2.6.x 内核中得到肯定。 
2、如果 Linux 系统没有配种某种时间同步机制(比如NTP),
   那么和闰秒无关,唯一导致的结果只是系统时间会比 UTC
   时间快一秒。 
3、Window Time Service 不支持闰秒,包括服务器和客户端。

回过头来考虑项目中碰到的这种情况,直接使用时间戳存储时间点会更精确些。最后, 提供下相关的测试脚本 ,看看你的环境是否也会有类似的问题。

-- EOF --

我的照片

嗨!我叫「明城」,八零后、技术男、伪苹果粉、微软无脑黑、宁波佬,现居杭州。

除了我的博客,同时也欢迎您访问我的 GitHubTwitterInstagram 主页。

这个 Blog 原先的名字叫 Gracecode.com 、现在叫 「無標題文檔」 。 其实无所谓叫什么名字,因为我曾经为这个名字伤透了脑筋。最后想到的这个名字都没啥特别的,说到 底是因为我实在给它不了个非常酷的名字。

如果您想联系我,可以发我邮件 echo bWluZ2NoZW5nQG91dGxvb2suY29tCg== | base64 -d

注:本站点所持观点仅代表个人意见,不代表所服务公司的立场。

文章

项目

微信公众号