本博客Nginx 配置之安全篇
之前有細心的朋友問我,為什麼你的博客副標題是「專注WEB 端開發」,是不是少了「前端」的「前」。我想說的是,儘管我從畢業到現在七年左右的時間一直都在專業前端團隊從事前端相關工作,但這並不意味著我的知識體係就必須局限於前端這個範疇內。現在比較流行「全棧工程師」的概念,我覺得全棧意味著一個項目中,各個崗位所需要的技能你都具備,但並不一定意味著你什麼都需要做。你需要做什麼,更多是由能力、人員配比以及成本等各個因素所決定。儘管我現在的工作職責是在WEB 前端領域,但是我的關注點在整個WEB 端。 我接觸過的有些前端朋友,從一開始就把自己局限在一個很小的範圍之中,這在大公司到也無所謂,大公司分工明確,基礎設施齊全,你只要做好自己擅長的那部分就可以了。但是當他們進入創業公司之後,會發現一下子來了好多之前完全沒有接觸過的東西,十分被動。 去年我用Lua + OpenResty替換了線上千萬級的PHP + Nginx服務,至今穩定運行,算是前端之外的一點嘗試。我一直認為學習任何知識很重要的一點是實踐,所以我一直都在折騰我的VPS,進行各種WEB安全、優化相關的嘗試。我打算從安全和性能兩方面介紹一下本博客所用Nginx的相關配置,今天先寫安全相關的。 隱藏不必要的信息 大家可以看一下我的博客請求響應頭,有這麼一行server: nginx,說明我用的是Nginx服務器,但並沒有具體的版本號。由於某些Nginx漏洞只存在於特定的版本,隱藏版本號可以提高安全性。這只需要在配置裡加上這個就可以了: server_tokens off; 如果想要更徹底隱藏所用Web Server,可以修改Nginx源碼,把Server Name改掉再編譯,具體步驟可以自己搜索。需要提醒的是:如果你的網站支持SPDY,只改動網上那些文章寫到的地方還不夠,跟SPDY有關的代碼也要改。更簡單的做法是改用Tengine這個Nginx的增強版,並指定server_tag為off或者任何想要的值就可以了。另外,既然想要徹底隱藏Nginx,404、500等各種出錯頁也需要自定義。 同樣,一些WEB語言或框架默認輸出的x-powered-by也會洩露網站信息,他們一般都提供了修改或移除的方法,可以自行查看手冊。如果部署上用到了Nginx的反向代理,也可以通過proxy_hide_header指令隱藏它: proxy_hide_header X-Powered-By; 禁用非必要的方法 由於我的博客只處理了GET、POST 兩種請求方法,而HTTP/1 協議還規定了TRACE 這樣的方法用於網絡診斷,這也可能會暴露一些信息。所以我針對GET、POST 以及HEAD 之外的請求,直接返回了444 狀態碼(444 是Nginx 定義的響應狀態碼,會立即斷開連接,沒有響應正文)。具體配置是這樣的: NGINXif ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } 合理配置響應頭 我的博客是由自己用ThinkJS 寫的Node 程序提供服務,Nginx 通過proxy_pass 把請求反向代理給Node 綁定的IP 和端口。在最終輸出時,我給響應增加了以下頭部: NGINXadd_header Strict-Transport-Security “max-age=31536000”; add_header X-Frame-Options deny; add_header X-Content-Type-Options […]
搭建微信订阅号后台服务
搭建微信订阅号后台服务 准备域名 任务时间:20min ~ 40min 微信公众平台需要配置服务器地址 URL 访问,在实验开始之前,我们要准备域名。 域名注册 如果您还没有域名,可以在腾讯云上选购,过程可以参考下面的视频。 视频 – 在腾讯云上购买域名 域名解析 域名购买完成后, 需要将域名解析到实验云主机上,实验云主机的 IP 为: <您的 CVM IP 地址> 在腾讯云购买的域名,可以到控制台添加解析记录,过程可参考下面的视频: 视频 – 如何在腾讯云上解析域名 域名设置解析后需要过一段时间才会生效,通过 ping 命令检查域名是否生效 [?],如: ping www.yourmpdomain.com 如果 ping 命令返回的信息中含有你设置的解析的 IP 地址,说明解析成功。 注意替换下面命令中的 www.yourmpdomain.com 为您自己的注册的域名 申请微信个人订阅号 任务时间:5min ~ 10min 在开始搭建我们的订阅号服务器之前,需要先拿到订阅号相关信息。 注册开发者账号 如果你还不是微信订阅号开发者,请先在微信公众平台注册: https://mp.weixin.qq.com 具体注册流程可参考如下视频: 视频 – 注册开发者账号 若您已注册,请点击下一步。 获取微信订阅号公众平台认证字段信息 我们需要获取3个字段:AppID Token EncodingAESKey。 登录微信公众平台,依次进入 开发 – 基本配置 可以拿到 AppID。 在基本配置 – 服务器配置 – 修改配置 表单中: […]
静态文件用nginx直接serve
#css|js|ico|gif|jpg|jpeg|png|txt|html|htm|xml|swf|wav这些都是静态文件,但应分辨,js、css可能经常会变,过期时间应小一些,图片、html基本不变,过期时间可以设长一些 location ~* ^.+\.(ico|gif|jpg|jpeg|png|html|htm)$ { root /var/www/poseidon/root/static; access_log off; expires 30d; } location ~* ^.+\.(css|js|txt|xml|swf|wav)$ { root /var/www/poseidon/root/static; access_log off; expires 24h; } #注:location不包括?后面带的参数,所以以上正则可以匹配http://192.168.1.16/image/sxxx.jpg?a=xxx
Nginx的worker_cpu_affinity详解
配置文件中的worker_cpu_affinity可以用来绑定每个nginx进程所使用的CPU 官方的解释是: #—————————-引用文字-开始—————————- Syntax: worker_cpu_affinity cpumask [cpumask…] Default: none Linux only. With this option you can bind the worker process to a CPU, it calls sched_setaffinity(). For example, worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; Bind each worker process to one CPU only. worker_processes 2; worker_cpu_affinity 0101 1010; Bind the first worker to CPU0/CPU2, bind […]
resin + nginx
download the upstream jvm route from http://code.google.com/p/nginx-upstream-jvm-route/ [root@web1 nginx-1.2.0]# tar -zxf nginx-upstream-jvm-route-0.1.tar.gz [root@web1 nginx-1.2.0]# patch -p0 ./nginx_upstream_jvm_route/jvm_route.patch [root@web1 nginx-1.2.0]# ./configure –sbin-path=/usr/sbin/ –conf-path=/etc/nginx/nginx.conf –with-http_stub_status_module –with-http_ssl_module –add-module=./nginx_upstream_jvm_route edit /etc/nginx/nginx.conf add upstream resin_proxy { server 127.0.0.1:85 srun_id=app-by1 max_fails=2 fail_timeout=10s weight=200; //负载均衡 server web3:85 srun_id=app-by2 max_fails=2 fail_timeout=10s weight=200; //负载均衡 jvm_route $cookie_JSESSIONID|sessionid; } server { listen 80; server_name […]
varnish,squid,apache,nginx缓存文件比较
一,测试环境 1,硬件是奔腾双核,机子三年前买的。系统是archlinux 2,测试varnish和squid的时候,web服务用的apache 3,测试apache的时候,启动了5个进程,不过随着压力的增加,进程会增加的。 4,测试nginx的时候,启动了十个nginx进程,20个php-cgi进程 5,varnish,squid,nginx用的是反向代理的形势,也就是说访问图片的时候,要先透过缓存工具 二,测试 1,varnish [root@BlackGhost bin]# /usr/local/bin/webbench -c 100 -t 20 http://127.0.0.1:8080/00/01/RwGowEtWvcQAAAAAAAAWHH0Rklg81.gif Webbench – Simple Web Benchmark 1.5 Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. Benchmarking: GET http://127.0.0.1:8080/00/01/RwGowEtWvcQAAAAAAAAWHH0Rklg81.gif 100 clients, running 20 sec. Speed=476508 pages/min, 47258114 bytes/sec. Requests: 158836 susceed, 0 failed. 访问了这么次,没有缓存只有一次,效率真的很高。 2,squid [root@BlackGhost bin]# /usr/local/bin/webbench -c […]
nginx+resin 使用中文域名解决方案。
xxx中文域名.中国 这样的域名在resin下会出错: [15:34:31.628] {hmux-127.0.0.1:6801-5} java.lang.StringIndexOutOfBoundsException: String index out of range: 9[15:34:31.628] {hmux-127.0.0.1:6801-5} at java.lang.String.charAt(String.java:687)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.host.DomainName.decode(DomainName.java:205)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.host.DomainName.fromAscii(DomainName.java:86)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.host.HostContainer.buildInvocation(HostContainer.java:305)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.cluster.Server.buildInvocation(Server.java:915)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.dispatch.DispatchServer.buildInvocation(DispatchServer.java:209)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.hmux.HmuxRequest.handleRequest(HmuxRequest.java:427)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.server.port.TcpConnection.run(TcpConnection.java:603)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:721)[15:34:31.628] {hmux-127.0.0.1:6801-5} at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:643)[15:34:31.628] {hmux-127.0.0.1:6801-5} at java.lang.Thread.run(Thread.java:619)[15:34:31.628] {hmux-127.0.0.1:6801-5} java.lang.RuntimeException: java.lang.StringIndexOutOfBoundsException: String index out of range: 9[15:34:31.628] {hmux-127.0.0.1:6801-5} at […]
Nginx源码分析-内存池
Nginx的内存池实现得很精巧,代码也很简洁。总的来说,所有的内存池基本都一个宗旨:申请大块内存,避免“细水长流”。 一、创建一个内存池 nginx内存池主要有下面两个结构来维护,他们分别维护了内存池的头部和数据部。此处数据部就是供用户分配小块内存的地方。 //该结构用来维护内存池的数据块,供用户分配之用。 typedef struct { u_char *last; //当前内存分配结束位置,即下一段可分配内存的起始位置 u_char *end; //内存池结束位置 ngx_pool_t *next; //链接到下一个内存池 ngx_uint_t failed; //统计该内存池不能满足分配请求的次数 } ngx_pool_data_t; //该结构维护整个内存池的头部信息。 struct ngx_pool_s { ngx_pool_data_t d; //数据块 size_t max; //数据块的大小,即小块内存的最大值 ngx_pool_t *current; //保存当前内存池 ngx_chain_t *chain; //可以挂一个chain结构 ngx_pool_large_t *large; //分配大块内存用,即超过max的内存请求 ngx_pool_cleanup_t *cleanup; //挂载一些内存池释放的时候,同时释放的资源。 ngx_log_t *log; }; 有了上面的两个结构,就可以创建一个内存池了,nginx用来创建一个内存池的接口是:ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log)(位于src/core/ngx_palloc.c中);调用这个函数就可以创建一个大小为size的内存池了。这里,我用内存池的结构图来展示,就不做具体的代码分析了。 ngx_create_pool接口函数就是分配上图这样的一大块内存,然后初始化好各个头部字段(上图中的彩色部分)。红色表示的四个字段就是来自于上述的第一个结构,维护数据部分,由图可知:last是用户从内存池分配新内存的开始位置,end是这块内存池的结束位置,所有分配的内存都不能超过end。蓝色表示的max字段的值等于整个数据部分的长度,用户请求的内存大于max时,就认为用户请求的是一个大内存,此时需要在紫色表示的large字段下面单独分配;用户请求的内存不大于max的话,就是小内存申请,直接在数据部分分配,此时将会移动last指针。 二、分配小块内存(size <= max) […]