在我写这篇文章前,查阅了近百篇ATS教程,几乎没有一篇可直接用于生产环境。
从逐一尝试Varnish、Nginx、HAProxy缓存功能,到最终确定使用ATS,期间一次又一次采坑,耗费了大量时间。仅从零学习ATS官方文档及生产环境调试这一项,时间成本就在1~2周左右。
最终将这片文章写成教学,对于一个技术人员而言,能够直接将ATS的入门时间降低至几小时,没有做过多排版见谅。
一、程序部署
安装所需的程序库
AlmaLinux 8
sudo dnf -y upgrade sudo dnf -y install epel-release sudo dnf -y install gcc gcc-c++ wget bzip2 pkgconfig autoconf automake libtool iptables-services libmaxminddb-devel libwebp-devel ImageMagick-c++-devel tcl-devel expat-devel pcre-devel perl-ExtUtils-MakeMaker perl-CPAN libaio-devel libcap libcap-devel libunwind libunwind-devel hiredis hiredis-devel curl curl-devel ncurses ncurses-devel luajit luajit-devel brotli-devel zlib-devel openssl-devel numactl hwloc http://mirror.centos.org/centos/8-stream/PowerTools/x86_64/os/Packages/hwloc-devel-2.2.0-3.el8.x86_64.rpm
AlmaLinux 9
sudo dnf -y upgrade sudo dnf -y install epel-release dnf -y install gcc gcc-c++ wget bzip2 pkgconfig autoconf automake libtool iptables-services libwebp-devel ImageMagick-c++-devel tcl-devel expat-devel pcre-devel perl-ExtUtils-MakeMaker perl-CPAN libaio-devel libcap libcap-devel libunwind libunwind-devel hiredis hiredis-devel curl curl-devel ncurses ncurses-devel luajit luajit-devel brotli-devel zlib-devel openssl-devel numactl hwloc https://repo.almalinux.org/almalinux/9/AppStream/x86_64/os/Packages/libmaxminddb-1.5.2-3.el9.x86_64.rpm https://repo.almalinux.org/almalinux/9/AppStream/x86_64/os/Packages/hwloc-devel-2.4.1-5.el9.x86_64.rpm
下载源码包
mkdir -p /ats/src cd /ats/src wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz wget https://dlcdn.apache.org/trafficserver/trafficserver-9.1.3.tar.bz2 wget https://github.com/jemalloc/jemalloc/releases/download/3.6.0/jemalloc-3.6.0.tar.bz2
编译Jemalloc
tar -jxvf jemalloc-3.6.0.tar.bz2 cd jemalloc-3.6.0/ ./configure make make install ln -s /usr/local/lib/libjemalloc* /lib64/ cd ../ rm -rf jemalloc-3.6.0
编译openssl
tar -zxvf openssl-1.1.1q.tar.gz cd openssl-1.1.1q/ ./config shared enable-mdc2 enable-md2 --prefix=/ats/openssl make make install cd ../ rm -rf openssl-1.1.1q
创建用户和组
/usr/sbin/groupadd www /usr/sbin/useradd -g www www
编译安装ATS
tar -jxvf trafficserver-9.1.3.tar.bz2 cd trafficserver-9.1.3/ ./configure --prefix=/ats --enable-experimental-plugins --with-user=www --with-group=www --with-pcre --with-zlib --with-brotli --with-hiredis --with-luajit --with-jemalloc --with-openssl=/ats/openssl make make install cd ../
考虑到生产环境的服务器在线编译成本较高,程序库与编译参数附带了部分默认未开启的功能,避免使用时再次编译。
编译过程耗时较长,可在编译时进行参数配置的步骤,以节约部署时间。
加入服务
cat > /etc/systemd/system/ats.service <<EOF [Unit] Description=Apache Traffic Server After=syslog.target network.target [Service] Type=forking ExecStart=/ats/bin/trafficserver start ExecReload=/ats/bin/traffic_ctl config reload ExecStop=/ats/bin/trafficserver stop Restart=on-abort [Install] WantedBy=multi-user.target EOF
开启服务
systemctl start ats systemctl enable ats
二、参数配置
在生产环境中,至少需要修改10个配置文件,才能保证ATS的基础运行,这会让初学者感到崩溃。而当使用优化过的配置文件模板时,实际只需要修改几处配置,即可快速在生产环境中部署。
配置文件教学部分,更多给出的是如何完成基础配置的思路,能够让初学者在最短时间从零到一掌握ATS的使用,之后再去查看官方文档,将大幅度降低学习与理解的成本,这也是写这篇教学文章的初衷。
为了方便理解,这里将多个配置文件进行了分类:
配置文件目录 | /ats/etc/trafficserver/ |
基础配置 | records.config |
插件配置 | plugin.config header_rewrite.config |
缓存配置 | storage.config volume.config hosting.config cache.config |
域名配置 | remap.config parent.config ssl_multicert.config |
基础配置
records.config 是ATS的主配置文件,分享一个生产环境的模板
# # *NOTE*: All options covered in this file should be documented in the docs: # # https://docs.trafficserver.apache.org/records.config # # Thread configurations CONFIG proxy.config.exec_thread.autoconfig INT 0 CONFIG proxy.config.exec_thread.autoconfig.scale FLOAT 1.0 CONFIG proxy.config.exec_thread.limit INT 16 CONFIG proxy.config.accept_threads INT 0 CONFIG proxy.config.task_threads INT 32 CONFIG proxy.config.cache.threads_per_disk INT 16 CONFIG proxy.config.exec_thread.listen INT 1 CONFIG proxy.config.exec_thread.affinity INT 0 # Specify server addresses and ports to bind for HTTP and HTTPS CONFIG proxy.config.http.server_ports STRING 80 443:proto=http2;http:ssl # Via / Server headers CONFIG proxy.config.http.insert_request_via_str INT 1 CONFIG proxy.config.http.insert_response_via_str INT 2 CONFIG proxy.config.http.response_via_str STRING ATS CONFIG proxy.config.http.response_server_str STRING Cache Server # Parent proxy configuration, in addition to these settings also see parent.config CONFIG proxy.config.http.parent_proxy.retry_time INT 300 CONFIG proxy.config.http.parent_proxy.connect_attempts_timeout INT 30 CONFIG proxy.config.http.forward.proxy_auth_to_parent INT 0 CONFIG proxy.config.http.uncacheable_requests_bypass_parent INT 1 # HTTP connection timeouts (secs) CONFIG proxy.config.http.keep_alive_no_activity_timeout_in INT 60 CONFIG proxy.config.http.keep_alive_no_activity_timeout_out INT 60 CONFIG proxy.config.http.transaction_no_activity_timeout_in INT 30 CONFIG proxy.config.http.transaction_no_activity_timeout_out INT 30 CONFIG proxy.config.http.transaction_active_timeout_in INT 900 CONFIG proxy.config.http.transaction_active_timeout_out INT 0 CONFIG proxy.config.http.accept_no_activity_timeout INT 60 CONFIG proxy.config.net.default_inactivity_timeout INT 86400 # Origin server connect attempts CONFIG proxy.config.http.connect_attempts_max_retries INT 3 CONFIG proxy.config.http.connect_attempts_max_retries_dead_server INT 1 CONFIG proxy.config.http.connect_attempts_rr_retries INT 3 CONFIG proxy.config.http.connect_attempts_timeout INT 30 CONFIG proxy.config.http.post_connect_attempts_timeout INT 1800 CONFIG proxy.config.http.down_server.cache_time INT 300 CONFIG proxy.config.http.background_fill_active_timeout INT 0 CONFIG proxy.config.http.background_fill_completed_threshold FLOAT 0.000000 # Negative response caching, for redirects and errors CONFIG proxy.config.http.negative_caching_enabled INT 1 CONFIG proxy.config.http.negative_caching_lifetime INT 10 CONFIG proxy.config.http.negative_caching_list STRING 305 403 404 414 444 500 501 502 503 504 # Proxy users variables CONFIG proxy.config.http.insert_client_ip INT 1 CONFIG proxy.config.http.insert_squid_x_forwarded_for INT 1 # Security CONFIG proxy.config.http.push_method_enabled INT 0 # Enable / disable HTTP caching CONFIG proxy.config.http.cache.http INT 1 # Cache control CONFIG proxy.config.http.cache.ignore_client_cc_max_age INT 1 CONFIG proxy.config.http.normalize_ae INT 0 CONFIG proxy.config.http.cache.cache_responses_to_cookies INT 1 CONFIG proxy.config.http.cache.cache_urls_that_look_dynamic INT 1 CONFIG proxy.config.http.cache.when_to_revalidate INT 0 CONFIG proxy.config.http.cache.required_headers INT 2 CONFIG proxy.config.http.cache.ignore_client_no_cache INT 1 # Heuristic cache expiration CONFIG proxy.config.http.cache.heuristic_min_lifetime INT 3600 CONFIG proxy.config.http.cache.heuristic_max_lifetime INT 259200 CONFIG proxy.config.http.cache.heuristic_lm_factor FLOAT 0.10 # Network CONFIG proxy.config.net.connections_throttle INT 65535 CONFIG proxy.config.net.max_connections_in INT 65535 CONFIG proxy.config.net.max_requests_in INT 0 # RAM and disk cache configurations CONFIG proxy.config.cache.ram_cache.size INT 1024M CONFIG proxy.config.cache.ram_cache_cutoff INT 4194304 CONFIG proxy.config.cache.target_fragment_size INT 524288 CONFIG proxy.config.cache.ram_cache.compress INT 1 CONFIG proxy.config.cache.ram_cache.algorithm INT 0 CONFIG proxy.config.cache.ram_cache.use_seen_filter INT 0 CONFIG proxy.config.cache.limits.http.max_alts INT 5 CONFIG proxy.config.cache.max_doc_size INT 0 CONFIG proxy.config.cache.min_average_object_size INT 16384 CONFIG proxy.config.cache.enable_read_while_writer INT 2 CONFIG proxy.config.cache.read_while_writer.max_retries INT 10 CONFIG proxy.config.cache.read_while_writer_retry.delay INT 50 CONFIG proxy.config.http.cache.max_open_read_retries INT 5 CONFIG proxy.config.http.cache.open_read_retry_time INT 10 CONFIG proxy.config.http.cache.open_write_fail_action INT 5 # Logging Config CONFIG proxy.config.log.logging_enabled INT 3 CONFIG proxy.config.log.max_space_mb_for_logs INT 15000 CONFIG proxy.config.log.max_space_mb_headroom INT 1000 CONFIG proxy.config.log.rolling_enabled INT 1 CONFIG proxy.config.log.rolling_interval_sec INT 86400 CONFIG proxy.config.log.rolling_size_mb INT 10 CONFIG proxy.config.log.auto_delete_rolled_files INT 1 CONFIG proxy.config.log.periodic_tasks_interval INT 6 # These settings control remapping, and if the proxy allows (open) forward proxy or not CONFIG proxy.config.url_remap.remap_required INT 1 CONFIG proxy.config.url_remap.pristine_host_hdr INT 1 CONFIG proxy.config.reverse_proxy.enabled INT 1 # SSL configurations CONFIG proxy.config.ssl.client.verify.server.policy STRING PERMISSIVE CONFIG proxy.config.ssl.client.verify.server.properties STRING ALL CONFIG proxy.config.ssl.client.CA.cert.filename STRING NULL CONFIG proxy.config.ssl.server.cert.path STRING /ats/etc/ssl/ CONFIG proxy.config.ssl.server.private_key.path STRING /ats/etc/ssl/ CONFIG proxy.config.ssl.server.ticket_key.filename STRING ticket.key CONFIG proxy.config.ssl.server.cipher_suite STRING ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 CONFIG proxy.config.ssl.server.TLSv1_3.cipher_suites STRING TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 CONFIG proxy.config.ssl.server.groups_list STRING X25519:P-256:P-384 CONFIG proxy.config.ssl.ocsp.enabled INT 1 CONFIG proxy.config.ssl.ocsp.response.path STRING /ats/etc/ssl/ CONFIG proxy.config.ssl.TLSv1 INT 0 CONFIG proxy.config.ssl.TLSv1_1 INT 0 CONFIG proxy.config.ssl.TLSv1_2 INT 1 CONFIG proxy.config.ssl.TLSv1_3 INT 1 CONFIG proxy.config.ssl.session_cache INT 2 CONFIG proxy.config.ssl.session_cache.size INT 102400 CONFIG proxy.config.ssl.session_cache.num_buckets INT 256 CONFIG proxy.config.ssl.server.session_ticket.enable INT 1 CONFIG proxy.config.ssl.server.session_ticket.number INT 1 CONFIG proxy.config.ssl.server.max_early_data INT 0 CONFIG proxy.config.ssl.server.allow_early_data_params INT 0 # Debugging CONFIG proxy.config.diags.debug.enabled INT 0 CONFIG proxy.config.diags.debug.tags STRING http|dns # ToDo Undocumented CONFIG proxy.config.dump_mem_info_frequency INT 0 CONFIG proxy.config.http.slow.log.threshold INT 0 # Http UI Endpoints CONFIG proxy.config.http_ui_enabled INT 1
需要根据生产环境的实际情况,调整模板中的参数
proxy.config.exec_thread.limit 每个CPU核心启动的线程数,一些知名云服务厂商提供的数据表明,设置为16性能最佳,如果服务器的CPU单核性能较弱,可以适当减少这个数值
proxy.config.task_threads 处理任务的总线程数,建议设置为CPU的核心数x每个CPU核心分配的线程数。 例如:一台双核服务器,当proxy.config.exec_thread.limit设置为16时,应将该参数设置为32
proxy.config.cache.threads_per_disk 用于处理硬盘I/O的线程数,由于已开启内存缓存会大幅度降低硬盘I/0,一般设置为单核心的线程数即16
proxy.config.exec_thread.affinity 该参数用于将线程与处理单元进行绑定,默认数值1是将线程分配给NUMA节点,其目的是防止ATS进程跨芯片以提高性能,当服务器并非多路物理机时,建议设置为0与机器绑定。 设置为1时,应使用numactl命令控制ATS使用的CPU和内存,例如: numactl --cpunodebind=0,1 -m 0,1 trafficserver start
proxy.config.http.response_server_str 自定义header标头中server内容,安全考虑对访问者隐藏ATS信息
proxy.config.http.insert_request_via_str proxy.config.http.insert_response_via_str 这两个参数用于配置header标头中的via信息,查看缓存的命中情况。 很多教程都是建议调试结束后关闭via信息,而实际观察一些知名的CDN标头信息,大多是没有隐藏的,所以建议调试结束后,通过重写header的方式隐藏ATS信息,这篇教学文章采用的就是这种方法,具体可以参考文章后面的重写header部分。 将proxy.config.http.insert_response_via_str设置为2时,刷新页面查看header中的via信头,一般会看到三个不同的值: [cHs f ] 命中缓存,无需回源 [cMsSfW] 未命中缓存,请求回源,如内容在缓存规则中则请求内容写入缓存 [cSsSfU] 命中过期缓存,请求回源,并更新ATS服务器上的缓存 也可以通过traffic_via命令查看这些数值表示的含义,例如: /ats/etc/bin/traffic_via '[cHs f ]'
proxy.config.http.normalize_ae 这是一个几乎会让所有用户踩坑的参数,而且还是两次。 [坑一] proxy.config.http.normalize_ae_gzip 是该参数的前身,ATS9.0之后的版本已不再使用,在写这篇教学文章前,没找到任何一篇教学文章修改了此处,这将导致新参数以默认为1的数值运行,结果就是如果源服务器开启了br压缩,将造成ATS缓存服务器的br与gzip全部失效 [坑二] 官方文档与很多教程都建议开启该参数,此处严重误导用户,这个参数开启后的实际效果是,只会缓存gzip或br压缩的文件,其它文件将不再被缓存。正确的配置方式:应将该参数设置为0并在源服务器开启br与gzip压缩
proxy.config.cache.ram_cache.size 设置内存缓存大小,默认是硬盘缓存大小的1% 需要注意的是,部分系统服务与TCP连接也会消耗内存,所以设置内存缓存大小时,应计算这些情况后,再去使用更多的内存缓存
proxy.config.cache.ram_cache_cutoff 内存缓存的最大文件尺寸限制,默认4MB,可以根据实际情况进行调整,修改参数时应注意大小单位,例如1MB应使用数值1048576表示(1x1024x1024)
proxy.config.cache.max_doc_size 全部缓存的最大文件尺寸限制,默认不限制
proxy.config.log.max_space_mb_for_logs 日志文件大小限制,默认25000即25000MB,建议根据实际情况调整
proxy.config.ssl.server.cert.path proxy.config.ssl.server.private_key.path proxy.config.ssl.ocsp.response.path 这三个参数用于指向证书目录,可根据实际情况调整目录
proxy.config.ssl.server.max_early_data proxy.config.ssl.server.allow_early_data_params 这两个参数用于开启0-RTT,考虑到重放攻击的安全问题,配置模板中没有开启 开启0-RTT参数示例: CONFIG proxy.config.ssl.server.max_early_data INT 16384 CONFIG proxy.config.ssl.server.allow_early_data_params INT 1
其余参数使用优化模板中的默认配置即可,如需深度调试,请参考官方文档。
插件配置
plugin.config 是ATS的插件配置文件
建议开启压缩、ESI、重写header这些个比较常用的插件
compress.so esi.so --private-response --first-byte-flush header_rewrite.so /ats/etc/trafficserver/header_rewrite.config
需要注意 plugin.config 是全局开启插件功能,如果仅需要单域名开启某个插件,应在 remap.config 中配置,更多插件的调用请参考官方文档。
header_rewrite.config 是重写header插件的配置文件,需自行创建
# # header_rewrite.config # # Documentation: # https://docs.trafficserver.apache.org/admin-guide/plugins/header_rewrite.en.html # cond %{READ_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:Strict-Transport-Security} ="" [AND] cond %{INBOUND:TLS} /./ set-header Strict-Transport-Security "max-age=31536000; preload" cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:via} ="http/1.1 traffic_server (ATS [cRs f ])" set-header via "x-cache Hit" cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:via} ="http/1.1 traffic_server (ATS [cMsSfW])" set-header via "x-cache Miss" cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:via} ="http/1.1 traffic_server (ATS [cSsSfU])" set-header via "x-cache Miss" cond %{SEND_RESPONSE_HDR_HOOK} set-header via "x-cache Get"
以上rewrite规则中,加入了两个功能:
HSTS cond %{READ_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:Strict-Transport-Security} ="" [AND] cond %{INBOUND:TLS} /./ set-header Strict-Transport-Security "max-age=31536000; preload" [坑] 在records.config对HSTS也是有配置选项的,但没有preload功能,所以应使用重写header的方式开启
Via信头重写 cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:via} ="http/1.1 traffic_server (ATS [cRs f ])" set-header via "x-cache Hit" cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:via} ="http/1.1 traffic_server (ATS [cMsSfW])" set-header via "x-cache Miss" cond %{SEND_RESPONSE_HDR_HOOK} [AND] cond %{HEADER:via} ="http/1.1 traffic_server (ATS [cSsSfU])" set-header via "x-cache Miss" cond %{SEND_RESPONSE_HDR_HOOK} set-header via "x-cache Get" 主要是用于隐藏ATS信息,也方便查看缓存命中情况 [坑] 需要注意,最后一行加入了一个Get状态,原因是重写header的操作会发生在缓存处理之前,简单来说,假设我们访问一个没有被缓存的文件: 第一次访问为[cMsSfW]或[cSsSfU]的状态,通过重写标记Miss 第二次访问为[cRs f ]状态,通过重写标记为Hit 但实际会发现,第二次访问时,重写并未生效,依旧显示为[cRs f ],所以需要加入一个Get状态,来处理这种特殊情况,最终效果: 第一次访问为[cMsSfW]或[cSsSfU]的状态,通过重写标记Miss 第二次访问为[cRs f ]状态,重写发生在缓存处理前,通过重写标记为Get 第三次访问为[cRs f ]状态,通过重写标记Hit
更多的重写header用法请参考官方文档。
缓存配置
storage.config 是硬盘缓存的配置文件
一般情况下仅需调整缓存占用硬盘的空间即可,例如配置10GB硬盘缓存空间
var/trafficserver 10240M
其中 var/trafficserver 为相对地址,可更改为绝对地址
/ats/var/trafficserver 10240M
也可以使用整块硬盘作为缓存空间,具体方法可以参考官方文档
volume.config 用于创建不同大小的缓存卷
如果以内存缓存为主,这个配置文件可以留空不做任何修改;
如果更依赖硬盘缓存,需要减少single-lock单锁压力,或是限制每个域名的硬盘缓存空间使用,在只有一块硬盘的情况下,应配置该文件来增加卷。
例如配置单硬盘增加3个卷:
volume=1 scheme=http size=20% volume=2 scheme=http size=40% volume=3 scheme=http size=40%
分配卷时,建议每个卷的空间高于内存缓存的大小,多硬盘的配置请参考官方文档。
hosting.config 用于为每个域名分配缓存卷
如果 volume.config 配置留空,则该文件也留空即可。
如果 volume.config 创建了多个缓存卷,例如已创建3个缓存卷,则应修改配置文件
hostname=* volume=1,2,3
这里使用通配符,让全部域名平均分布在全部缓存卷中,如果想为域名指定缓存卷,可修改为:
hostname=aaa.com volume=1 hostname=bbb.com volume=2,3 hostname=* volume=1,2,3 在配置文件中,有hostname与domain两种参数,建议使用hostname以更灵活的配置域名,如使用domain参数则所有子域名也会生效。 [坑] 即使为域名指向了存储卷,也一定要加入一条hostname=*参数且volume必须覆盖全部缓存卷,否则会引起部分缓存控制功能失效。
cache.config 是缓存规则的配置文件
分享一个通用的配置
url_regex=.* suffix=ashx action=never-cache url_regex=.* suffix=asp action=never-cache url_regex=.* suffix=aspx action=never-cache url_regex=.* suffix=do action=never-cache url_regex=.* suffix=jsp action=never-cache url_regex=.* suffix=php action=never-cache url_regex=.* suffix=shtml action=never-cache url_regex=.* suffix=bmp ttl-in-cache=7d url_regex=.* suffix=csv ttl-in-cache=7d url_regex=.* suffix=doc ttl-in-cache=7d url_regex=.* suffix=docx ttl-in-cache=7d url_regex=.* suffix=eot ttl-in-cache=7d url_regex=.* suffix=ico ttl-in-cache=7d url_regex=.* suffix=less ttl-in-cache=7d url_regex=.* suffix=m3u8 ttl-in-cache=7d url_regex=.* suffix=odt ttl-in-cache=7d url_regex=.* suffix=otf ttl-in-cache=7d url_regex=.* suffix=pdf ttl-in-cache=7d url_regex=.* suffix=ppt ttl-in-cache=7d url_regex=.* suffix=pptx ttl-in-cache=7d url_regex=.* suffix=rtf ttl-in-cache=7d url_regex=.* suffix=svg ttl-in-cache=7d url_regex=.* suffix=svgz ttl-in-cache=7d url_regex=.* suffix=swf ttl-in-cache=7d url_regex=.* suffix=ts ttl-in-cache=7d url_regex=.* suffix=ttf ttl-in-cache=7d url_regex=.* suffix=txt ttl-in-cache=7d url_regex=.* suffix=woff ttl-in-cache=7d url_regex=.* suffix=woff2 ttl-in-cache=7d url_regex=.* suffix=xls ttl-in-cache=7d url_regex=.* suffix=xlsx ttl-in-cache=7d url_regex=.* suffix=xml ttl-in-cache=7d url_regex=.* suffix=gif ttl-in-cache=30d url_regex=.* suffix=jpg ttl-in-cache=30d url_regex=.* suffix=jpeg ttl-in-cache=30d url_regex=.* suffix=png ttl-in-cache=30d url_regex=.* suffix=webp ttl-in-cache=30d url_regex=.* suffix=css revalidate=1d url_regex=.* suffix=js revalidate=1d url_regex=.* suffix=htm revalidate=1d url_regex=.* suffix=html revalidate=1d url_regex=.* scheme=http revalidate=1h url_regex=.* scheme=https revalidate=1h
其中的缓存时间应根据实际情况修改,示例中排除掉了一些大型静态文件,会根据scheme=http/https的规则来缓存。
下面给出一些常见的大型静态文件后缀,方便补充缓存规则:
7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip
ATS的缓存规则功能非常强大,示例中仅提供了基础的规则,更多高级规则使用请参考官方文档。
域名配置
remap.config 是域名映射配置文件
需要注意的是,即使只有一台回源服务器,也推荐使用均衡负载的回源示例:
map https://aaa.com http://aaa.com redirect http://aaa.com/ https://aaa.com/ map https://bbb.com https://bbb.com redirect http://bbb.com/ https://bbb.com/ .definefilter origin_only @action=allow @src_ip=127.0.0.1 @src_ip=192.168.0.1-192.168.0.254 .activatefilter origin_only regex_map https://.*.([0-9]+) http://{cache} regex_map http://.*.([0-9]+) http://{cache}
这种写法可能会让新手迷茫,解释一下含义:
map https://aaa.com http://aaa.com 第一个链接是ATS监听的域名与协议,第二个链接是该域名的回源地址与协议,其中回源地址是不会使用DNS解析的,而是根据parent.config的配置指向一个或多个IP地址。 [坑] 网络上几乎所有的教程,都是将第二个链接指向IP,又或是自定义一个虚拟的回源地址。实际上这种方法是有缺陷的,会引起部分缓存控制功能失效,所以回源地址应使用与域名相同的地址,回源协议优先推荐使用http,如果非内网或有劫持再使用https回源,源站建议开启0-RTT减少握手次数。
redirect http://aaa.com/ https://aaa.com/ 用于将http重定向至https
.definefilter origin_only @action=allow @src_ip=127.0.0.1 @src_ip=192.168.0.1-192.168.0.254 .activatefilter origin_only regex_map https://.*.([0-9]+) http://{cache} regex_map http://.*.([0-9]+) http://{cache} 用于开启UI管理页面,这个界面可以通过正则管理缓存,建议开启。需要限制哪些IP可以访问,可以是单个IP,也可以是IP段,通过一个或多个@src_ip参数定义即可。 必须将这段代码放置最底部,这里使用了.activatefilter指令来实现后面所有规则的访问IP限制,这种写法的好处,当有未绑定的域名指向ATS服务器时也会一起被禁止访问,兼顾了安全性。 [坑] 官方文档示例的写法,是用 map / http://{cache} 指令来映射UI管理页面,这种方式会造成重定向功能失效,原因是map的优先级高于redirect,所以应使用regex_map通过正则限制仅通过IP访问UI管理页面。
更多用法请参考官方文档。
parent.config 用于配置域名的回源地址及均衡负载
常用的配置示例:
dest_host=aaa.com parent="192.168.1.100:80" parent_is_proxy=false round_robin=strict dest_host=bbb.com parent="192.168.1.101:443|1.0, 192.168.1.102:443|2.0" parent_is_proxy=false round_robin=strict
需要配置的选项
dest_host=aaa.com 配置文件中的示例使用的是dest_domain参数,建议使用dest_host以更灵活的配置域名,如使用dest_domain参数则所有子域名也会指向配置的IP地址。 parent="192.168.1.100:80" 回源的IP地址,必须带有端口号,端口号由 remap.config 中配置的回源协议决定,默认情况下http回源使用80、https回源使用443,如果回源服务器只有一台或只有一个IP地址,参考该示例中的配置即可。 parent="192.168.1.101:443|1.0, 192.168.1.102:443|2.0" 如果有多个回源IP,应配置均衡负载,ATS的均衡负载附带故障转移功能,所以健康检测非必须配置,示例中使用轮训算法回源,建议在回源IP后面加入比例参数,实现更灵活的回源控制。
更多复杂的回源规则配置,请参考官方文档。
ssl_multicert.config 是SSL证书的配置文件
需要先将域名的ssl证书与秘钥放置在records.config配置指向的证书目录中
如果该目录不存在,应使用mkdir命令创建,例如:
mkdir -p /ats/etc/ssl
然后对ssl_multicert.config进行如下配置:
dest_ip=* ssl_hostname=aaa.com ssl_cert_name=aaa.cer ssl_key_name=aaa.key dest_ip=* ssl_hostname=bbb.com ssl_cert_name=bbb.cer ssl_key_name=bbb.key ssl_ocsp_name=bbb.cer
推荐使用acme.sh脚本管理证书的自动更新:
#下载与安装脚本 curl https://get.acme.sh | sh alias acme.sh=~/.acme.sh/acme.sh #添加DNS的API秘钥 #DPI_Id、DPI_Key是DNSPod国际版的参数示例 #其它DNS厂商的参数查阅https://github.com/acmesh-official/acme.sh/wiki/dnsapi export DPI_Id="your id" export DPI_Key="your key" export ACCOUNT_EMAIL='your_email' #申请证书 #这里以DNSPod国际版申请aaa.com及其泛域名证书示例 acme.sh --issue --dns dns_dpi -d aaa.com -d *.aaa.com #安装证书 #这里使用 traffic_ctl config reload 命令实现SSL证书的热更新 acme.sh --installcert -d aaa.com -d *.aaa.com \ --key-file /ats/etc/ssl/aaa.com.key \ --fullchain-file /ats/etc/ssl/aaa.com.cer \ --reloadcmd "/ats/bin/traffic_ctl config reload" #配置自动更新脚本 acme.sh --upgrade --auto-upgrade
如需配置 OCSP Stapling 应注意:
判断证书的OCSP服务会不会返回Certificate 如不会返回,那么只需要配置ssl_cert_name与ssl_key_name即可。 一般情况下,ssl_ocsp_name与ssl_cert_name指向同一文件即可。 如果不清楚自己的证书是否需要配置ssl_ocsp_name,这里提供一种比较简单的方法,先配置ssl_cert_name与ssl_key_name,启动ATS后使用openssl指令测试: openssl s_client -connect 0.0.0.0:443 -servername aaa.com -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response" 如返回 OCSP response: OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response 说明OCSP开启成功 如返回 OCSP response: no response sent 应配置ssl_ocsp_name,重启ATS后再次使用相同指令测试。
[坑] ssl_hostname是一个隐藏参数,官方文档并未提及,官方文档的示例是使用dest_ip参数绑定回源IP地址,但这会造成一个问题,当源服务器上有多个域名时将无法处理,所以建议使用dest_ip=* ssl_hostname=aaa.com的写法。
这样配置适用于绝大多数情况,如果想了解更多SSL的配置,请参考官方文档。
当全部配置文件调试结束后:
首次应执行 systemctl restart ats 重启ATS服务;
之后修改个别参数,执行 systemctl reload ats 重新加载即可。
三、会话复用
运行ATS前应使用openssl指令创建一个会话票证,实现会话复用:
head -c48 /dev/urandom | openssl enc -base64 | head -c48 > /ats/etc/ssl/ticket.key
其中ticket.key的命名与位置,是在record.config中配置的:
CONFIG proxy.config.ssl.server.cert.path STRING /ats/etc/ssl/ CONFIG proxy.config.ssl.server.ticket_key.filename STRING ticket.key
当需要部署多台ATS服务器时,应考虑Session Ticket轮换后的同步问题。
为什么没有提及Seesion ID集群? 因为这是tls1.2时期产生的问题,随着tls1.3普及,大多数web服务使用tls1.2访问的占比几乎不超过1%,并且会越来越低,因此没必要再去部署Seesion ID集群。
Session Ticket的轮换与同步
考虑到安全问题,Session Ticket是需要定期轮换的,当多台服务器上的Ticket不同步时,同一用户访问至不同的ATS服务器时,将无法实现会话复用以减少TLS的握手次数。
ATS有提供会话复用集群插件,但不推荐使用插件实现。因为当无需考虑Seesion ID同步的问题后,只需要解决Session Ticket轮换后的同步问题即可。
为什么ATS可以原生实现会话复用? 以Nginx为例,tls1.3依旧需要使用lua+memcached集群的根本原因,是当更新了Ticket后,Nginx是无法通过reload方式来热更新Ticket的,所以需要使用LUA来解决这一问题。 而ATS却可以通过traffic_ctl config reload方式热更新Ticket,从而简化相关的部署。
这里给出一种相对简单的轮换与同步思路:
在一台源服务器上,创建一个用于生成ticket的脚本
vi /etc/newticket
head -c48 /dev/urandom | openssl enc -base64 | head -c48 > /data/htdocs/wwwroot/ticket.key
应保证 /data/htdocs/wwwroot 目录能够被ATS服务器通过http或https访问到,建议设置为仅允许ATS服务器的IP访问。
使用 crontab -e 命令创建定时任务,每天生成一个新的ticket.key
0 0 * * * /etc/newticket
之后在每台ATS服务器上使用 crontab -e 命令创建定时任务,每天在访问人数较少的时间更新ticket.key
0 2 * * * curl https://ticketdomain.com/ticket.key > /tmp/temp_ticket.key && cat /tmp/temp_ticket.key > /ats/etc/ssl/ticket.key && /ats/bin/traffic_ctl config reload
SSL证书也可以采用相同的思路实现同步更新。
四、缓存控制
ATS可以通过执行traffic_server -Cclear命令清空全部缓存,这种方式需要停止ATS服务后才能使用
systemctl stop ats && /ats/bin/traffic_server -Cclear && systemctl restart ats
ATS官方文档中提供的一种基础的缓存控制方式
curl -vX PURGE --resolve aaa.com:443:127.0.0.1 https://aaa.com/demo.css
上述是删除aaa.com域名根目录下demo.css文件缓存的示例,缺点很明显,无法实现批量删除,如何实现批量删除缓存,ATS官方文档并未提供说明。
这里可以利用ATS自带的Http UI Endpoints功能实现,在remap.config配置成功后,即可实现通过正则批量删除缓存,同时也支持删除单个文件的缓存。
curl http://1.2.3.4/delete_url?url=http://aaa.com/demo.css curl http://1.2.3.4/delete_regex?url=http://aaa.com/.*.css
示例中,1.2.3.4为ATS服务器的IP地址,http://aaa.com为回源地址并非访问地址,需注意回源协议是http还是https,示例第一行表示删除aaa.com域名根目录下demo.css文件的缓存,第二行表示删除aaa.com域名根目录下全部.css文件的缓存。
ATS运行过程中,可以通过工具查看缓存状态:
traffic_logstats -o aaa.com
/ats/bin/traffic_top
五、系统优化
执行命令 vi /etc/security/limits.conf 在最下方添加
* soft nofile 65535 * hard nofile 65535
修改ulimit连接数最大值
echo -e '\n\nulimit -SHn 65535\n' >> /etc/profile && source /etc/profile
执行命令 vi /etc/sysconfig/selinux 修改选项关闭SELINUX
SELINUX=disabled
保存后执行命令 /usr/sbin/sestatus -v 查看SELINUX状态
执行命令 vi /etc/sysctl.conf 优化内核参数
fs.file-max = 65535 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_syn_retries = 2 net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_keepalive_time = 65 net.ipv4.tcp_fin_timeout = 1 net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.ip_local_port_range = 1024 65500 net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 262144 net.core.netdev_max_backlog = 262144 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.core.wmem_default = 8388608 net.core.rmem_default = 8388608 net.ipv4.tcp_timestamps = 0 #net.ipv4.tcp_tw_recycle = 0 net.ipv4.tcp_mem = 94500000 915000000 927000000 net.ipv4.tcp_max_orphans = 3276800 net.ipv4.tcp_fastopen = 2
保存后执行 sysctl -p 使配置立即生效
六、攻击防御
配置iptables防火墙
如果安装了FirewallD,需要关闭FirewallD服务
systemctl stop firewalld && systemctl disable firewalld
执行命令 vi /etc/sysconfig/iptables 配置防火墙
*filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT
开启iptables防火墙服务
systemctl enable iptables systemctl restart iptables
基础防御DDOS与CC攻击,推荐使用ddos-deflate脚本
wget https://github.com/jgmdev/ddos-deflate/archive/master.zip -O ddos-deflate.zip unzip ddos-deflate.zip cd ddos-deflate-master ./install.sh cd ../ rm -rf ddos-deflate-master
执行 vi /etc/ddos/ddos.conf 修改以下参数后保存
#修改为iptables FIREWALL="iptables" #修改为自己的邮箱 EMAIL_TO="[email protected]"
重启 DDoS Deflate 服务
systemctl restart ddos
此时防御已经生效,会每5秒钟检测一次连接数量,默认当某个IP超过150个连接后会被禁止访问,可以通过执行netstat命令查看当前每个IP的连接数量
netstat -ntu | awk '{print $5}' | cut -d: -f1 | uniq -c | sort -n
建议执行 ddos -h 查看帮助,方便以后运维使用。
ddos-deflate脚本没有IP黑名单功能,可以使用ATS的IP限制功能补充
需要配置ip_allow.yaml文件,文件默认采用完整格式写法,建议修改为精简格式写法:
ip_allow: [ { apply: in, ip_addrs: 127.0.0.1, action: allow }, { apply: in, ip_addrs: "::1", action: allow }, { apply: in, ip_addrs: 0/0, action: deny, methods: [ PURGE, PUSH, DELETE ] }, { apply: in, ip_addrs: "::/0", action: deny, methods: [ PURGE, PUSH, DELETE ] } ]
当需要限制某个IP时,应在allow规则的下一行加入deny规则,请勿将deny规则加在最后一行,这样不会生效,示例如下:
ip_allow: [ { apply: in, ip_addrs: 127.0.0.1, action: allow }, { apply: in, ip_addrs: "::1", action: allow }, { apply: in, ip_addrs: 1.2.3.1, action: deny }, { apply: in, ip_addrs: 1.2.2.0/24, action: deny }, { apply: in, ip_addrs: 0/0, action: deny, methods: [ PURGE, PUSH, DELETE ] }, { apply: in, ip_addrs: "::/0", action: deny, methods: [ PURGE, PUSH, DELETE ] } ]
{ apply: in, ip_addrs: 1.2.3.1, action: deny }, 禁止IP 1.2.3.1 访问ATS { apply: in, ip_addrs: 1.2.2.0/24, action: deny }, 禁止IP 1.2.2.x 整个网段访问ATS
之后执行 systemctl reload ats 使规则生效。
至此,ATS的配置全部完成。