yew6n-aaaaa-aaaad-qaqrq-cai.icp0.io
Open in
urlscan Pro
2a00:fb01:400:200:5000:eeff:fe3d:aa0d
Public Scan
URL:
https://yew6n-aaaaa-aaaad-qaqrq-cai.icp0.io/Nginx/index.html
Submission: On December 18 via api from US — Scanned from FR
Submission: On December 18 via api from US — Scanned from FR
Form analysis
1 forms found in the DOMName: search —
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required="">
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"></path>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"></path>
</svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"></path>
</svg>
</button>
</nav>
</form>
Text Content
Skip to content notebook Nginx Type to start searching GitHub notebook GitHub * Home * Python Python * Python * Gist Python一些常用代码片段 * Course Python程序设计 * Programming Languages Programming Languages * BASH * BAT批处理 * C语言 * Java Java * Java * S2-045 * JavaScript * PHP * Web Web * CDN * cURL * Favorites Favorites * Favorites * Github Project Recommendation * 更多链接 * Flask * MySQL * Nginx Nginx Table of contents * Nginx思考题 * 普通资源允许POST * 不带后缀的文件当成php执行 * http跳转到https * 获得Let's encrypt免费https证书 * 使用方法: * 第一步: * 第二步,运行我的getcert.py(创建私钥并提交申请): * 使用acme.sh获得泛域名证书 * 配置安全的https * 反向代理之替换网页、JS中的文本 * 禁止git目录访问 * root与alias的区别 * 在bash on win10上使用Nginx * 使上一级服务知道用户IP * Nginx允许列目录 * 安全地使用SeaweedFS作为图片反向代理服务器 * Nginx配置 * 在http段中添加upstream * server段配置 * 修改后端特定header * 我还是想让nginx也能支持给seaweedfs上传文件 * 配置proxy_pass使用的DNS服务器 * Docker 我使用的seaweedfs启动命令 * 编译镜像 避免丢失filer数据 * 启动命令 * B服务器的实现 * 顺便附上Python库pyseaweed的使用 * proxy_pass 动态代理 * Nginx隐藏Server头 简单方式 * 使用阿里云函数计算定时更新https证书 * 入口 * 代码框架 * 更多说明 * web服务器上的部署 * 使用nfs存储Nginx日志 * 使用openresty Lua编程实现hook跳转 * 不同子域名反代到不同端口 * Nginx配置文件格式化 * RabbitMQ * Development Development * Developer * Docker * ETH * Git * Jekyll * Paper Reading * WindowsSoftware * Fuzzing Fuzzing * DFSan * Fun Fun * Bitcoin * Linux Linux * Linux-backup * Linux-setup * Linux-SSH * Linux-cli * Linux-VirtualBox * Ubuntu * My Projects My Projects * ZJU grs helper * CCF Badge Table of contents * Nginx思考题 * 普通资源允许POST * 不带后缀的文件当成php执行 * http跳转到https * 获得Let's encrypt免费https证书 * 使用方法: * 第一步: * 第二步,运行我的getcert.py(创建私钥并提交申请): * 使用acme.sh获得泛域名证书 * 配置安全的https * 反向代理之替换网页、JS中的文本 * 禁止git目录访问 * root与alias的区别 * 在bash on win10上使用Nginx * 使上一级服务知道用户IP * Nginx允许列目录 * 安全地使用SeaweedFS作为图片反向代理服务器 * Nginx配置 * 在http段中添加upstream * server段配置 * 修改后端特定header * 我还是想让nginx也能支持给seaweedfs上传文件 * 配置proxy_pass使用的DNS服务器 * Docker 我使用的seaweedfs启动命令 * 编译镜像 避免丢失filer数据 * 启动命令 * B服务器的实现 * 顺便附上Python库pyseaweed的使用 * proxy_pass 动态代理 * Nginx隐藏Server头 简单方式 * 使用阿里云函数计算定时更新https证书 * 入口 * 代码框架 * 更多说明 * web服务器上的部署 * 使用nfs存储Nginx日志 * 使用openresty Lua编程实现hook跳转 * 不同子域名反代到不同端口 * Nginx配置文件格式化 NGINX¶ 记录用到的配置,说不定你也能遇到这些特殊需求呢~ NGINX思考题¶ 请以批判的眼光阅读以下链接或者自行google,回答以下问题: http://www.nginx.cn/591.html 1. nginx.conf在你Linux的什么目录下?用什么命令知道的?修改配置后通过什么命令重新载入配置? 2. nginx.conf分为几个部分?我们需要关注的是哪个? 3. nginx.conf中怎么表示注释行?是否留意到include的行载入了额外的配置文件? 4. 如何增加一个虚拟主机,根据域名来区分访问不同的网站?访问者直接访问IP或者错误的域名会匹配到默认网站,怎么配置默认网站? 这些是更为进阶/发散的问题: 1. 静态内容:root与alias有何区别?访问403了怎么办? 2. 动态内容/反向代理:如何做负载均衡、文本替换? 3. 全站https和HTTP/2.0怎么配置? 4. Nginx是否有必要作为一个Docker容器运行?CentOS下Nginx镜像很大,怎么减小镜像大小? 5. Nginx的worker进程一般不是root权限的,那是怎么监听到80端口的? 6. Nginx在处理高并发的时候参数如何调优? 7. 如何在Nginx层面拦截sql注入、密码爆破等安全风险?VeryNginx 普通资源允许POST¶ error_page 405 =200 @405; 不带后缀的文件当成PHP执行¶ 这里的思路是用反向代理的方式简单实现 location /path/something { proxy_pass http://yourdomain/path/something.php; proxy_method GET; } 顺带拒绝掉对php后缀的猜测: location = /path/something.php { if ($remote_addr != '服务器自身IP') { return 404; } include fastcgi.conf; } HTTP跳转到HTTPS¶ location /{ rewrite ^ https://$host$request_uri? permanent; } 获得LET’S ENCRYPT免费HTTPS证书¶ 为简化操作,我写了一个更加方便的getcert.py 使用方法:¶ 第一步:¶ 配置相应网站的nginx conf中的server里面,加入这个: location /.well-known/acme-challenge { alias 保存密钥的目录; try_files $uri =404; } 记得运行后 nginx -s reload 第二步,运行我的GETCERT.PY(创建私钥并提交申请):¶ pushd 上述保存密钥的目录 wget https://raw.githubusercontent.com/zjuchenyuan/notebook/master/code/getcert.py ./getcert.py 文件名称 该证书包含的域名列表 例如这样就能获得一张涵盖zjusec.com三个子域名的证书:./getcert.py zjusec zjusec.com,www.zjusec.com,web.zjusec.com 具体来说,这个脚本会自动下载需要的acme_tiny.py和Let’s Encrypt的中间证书,调用openssl创建账号私钥和站点私钥,最终产生 名称.crt 名称.key。 使用ACME.SH获得泛域名证书¶ 泛域名解析需要使用DNS验证,就需要使用DNS服务的API,即使没有API只要配置一条CNAME指向一个有DNS API的域名即可 首先获得acme.sh git clone https://github.com/Neilpang/acme.sh 然后拿到cloudflare的API Key,托管b.com 需要拿到能用于a.com和*.a.com的证书,先配置CNAME(参考:https://github.com/Neilpang/acme.sh/wiki/DNS-alias-mode) _acme-challenge.a.com => _acme-challenge.b.com 执行命令咯: CF_Key=xxx CF_Email=xxx@example.com /root/acme.sh/acme.sh --issue --dns dns_cf -d '*.a.com' --challenge-alias b.com -d a.com --dnssleep 10 --fullchain-file /root/acom.crt --key-file /root/acom.key -f 解释:前面两个是配置环境变量,使用cloudflare所以指定–dns dns_cf,然后-d … –challenge-alias … -d … 指定域名和验证用的域名,–dnssleep 10等待10秒DNS生效(默认120秒没必要),–fullchain-file和–key-file 指定生成后把证书文件和密钥文件拷贝到哪 配置安全的HTTPS¶ 此处参考https://z.codes/ssl-lab-a-plus-configuration-for-nginx/ 首先从PPA安装nginx, 这样可以保证最新版 add-apt-repository ppa:nginx/stable apt update apt install nginx 创建DH随机质数: openssl dhparam -out /etc/ssl/dhparams.pem 2048 创建/etc/nginx/https.conf: listen 443 ssl http2; add_header Strict-Transport-Security "max-age=31536000" always; add_header Upgrade-Insecure-Requests "1"; add_header Content-Security-Policy "upgrade-insecure-requests"; ssl_dhparam /etc/ssl/dhparams.pem; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 114.114.114.114 valid=60s; resolver_timeout 2s; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_session_cache shared:SSL:10m; ssl_session_timeout 24h; ssl_buffer_size 1400; ssl_prefer_server_ciphers on; keepalive_timeout 600s; location ~* /\.(?!well-known\/) { deny all; } location ~* (?:\.(?:bak|conf|dist|fla|in[ci]|log|psd|sh|sql|sw[op])|~)$ { deny all; } include mime.types; 为需要启用https的站点,在/etc/nginx/sites-enabled/中写入conf文件 server { listen 443; server_name 域名1 域名2; access_log /tmp/access.log; error_log /tmp/error.log; ssl_certificate 密钥目录/名称.crt; ssl_certificate_key 密钥目录/名称.key; include https.conf 其他配置。。。 } 反向代理之替换网页、JS中的文本¶ 使用模块ngx_http_substitutions_filter_module,见Github: https://github.com/yaoweibin/ngx_http_substitutions_filter_module 需要重新编译nginx,Tip: nginx -V命令可以显示当前版本的nginx的编译参数 编译后就可以用啦,举个例子:微信的公众号文章页面为了节省用户流量,图片是把页面滚动至所在位置才加载的,代码上的差异就是img标签本应是src的改成了data-src,这里我们要做一个微信的反向代理网站,把data-src替换成src,则可以直接加载所有图片(唔。。。其实还不够,还需要考虑防盗链的问题);并且设置MIME类型包含Javascript subs_filter 需要替换掉的内容 替换后的文本; subs_filter data-src src; subs_filter_types application/x-javascript text/javascript appliation/x-javascript; 禁止GIT目录访问¶ 在server块中添加: location ~ /\. { return 404; } 相应的Apache可以在httpd.conf中添加: RedirectMatch 404 /\.git ROOT与ALIAS的区别¶ From: http://stackoverflow.com/questions/10631933/nginx-static-file-serving-confusion-with-root-alias 一句话概括,root对应的目录会加上location部分去找文件,而alias则不会 location /static/ { root /var/www/app/static/; autoindex off; } 如果我们这么写,那么访问static目录下的a.jpg就会去找/var/www/app/static/static目录下的a.jpg,如果没有这个static/static就会404 解决方法有两种: 如果location中的static就是真实目录,root中就不要写static了 location /static/ { root /var/www/app/; autoindex off; } 或者用alias就不会再加上location的部分: location /static/ { alias /var/www/app/static/; autoindex off; } -------------------------------------------------------------------------------- 在BASH ON WIN10上使用NGINX¶ 与Linux中安装类似,只要apt-get install nginx即可,但可能会发现nginx并不正常工作,日志中是这样的: [alert] 79#0: ioctl(FIOASYNC) failed while spawning "worker process" (22: Invalid argument) 解决方案:在/etc/nginx/nginx.conf中添加一行: master_process off; -------------------------------------------------------------------------------- 使上一级服务知道用户IP¶ proxy_set_header realip $remote_addr; 这样设置后,Nginx反向代理上一级服务会加上realip这个头,从而传递用户真实的IP(如果是代理则是代理的IP) -------------------------------------------------------------------------------- NGINX允许列目录¶ 加上autoindex on即可,后两项是为了 显示服务器时间而不是GMT时间 以及 以kB,MB,GB为单位显示大小而不是确切的字节数 location / { autoindex on; autoindex_localtime on; autoindex_exact_size off; } -------------------------------------------------------------------------------- 安全地使用SEAWEEDFS作为图片反向代理服务器¶ 想基于seaweedfs实现一个反向代理的缓存服务器,Nginx先请求A服务器(weedfs filer),如果还没有存下这张图片(返回404),切至B服务器(Python flask)去爬取图片并传至weedfs存储 seaweedfs的filer提供了按自己指定的路径上传下载功能(对象存储),就不需要再自己考虑怎么存储path与fid的对应关系了,直接按爬取源的路径存储即可 实现: NGINX配置¶ 在HTTP段中添加UPSTREAM¶ 注意把B服务器设置为backup 不要参与默认负载均衡 upstream up { server weedfs:8888; server 127.0.0.1:80 backup; } SERVER段配置¶ 我希望访问/images/hhh.jpg实际访问http://weedfs:8888/my_images/hhh.jpg 关键就是proxy_next_upstream location /images/ { rewrite ^/images(/.*)$ /my_images$1 break; proxy_pass http://up; proxy_next_upstream http_404; proxy_hide_header Content-Type; add_header Content-Type image/jpeg; limit_except GET { deny all; } } 在seaweedfs返回404的时候会继续请求http://127.0.0.1/my_images/hhh.jpg 这种rewrite是不会修改POST的url的。。。就很迷,另外允许用户POST上传也是不安全的,这里就直接禁止了非GET方法 修改后端特定HEADER¶ 这里用的是先删除proxy_hide_header再添加add_header 我还是想让NGINX也能支持给SEAWEEDFS上传文件¶ 不要死磕一个location嘛,再配置个呗: location /upload_images/ { rewrite ^/upload_images(/.*)$ $1 break; resolver 127.0.0.11 valid=10s; proxy_pass http://weedfs:8888/my_images$1; allow 127.0.0.0/8; deny all; } 这样配置的效果是POST /upload_images/相当于在POST http://weedfs:8888/my_images/ 与前述的GET配置是相同的后端路径,上传的文件(如/123.jpg)就传到了weedfs的http://weedfs:8888/my_images/123.jpg能通过/images/123.jpg访问到 配置PROXY_PASS使用的DNS服务器¶ 由于这个nginx是在Docker容器里面的,weedfs是另一个容器加入网络的时候指定的别名,所以注意上面的resolver设置为与容器/etc/resolv.conf一致的127.0.0.11 经过我测试,这个配置必须在location中才有效,放到http里面没用 DOCKER 我使用的SEAWEEDFS启动命令¶ 编译镜像 避免丢失FILER数据¶ 首先需要自己编译一个Docker镜像,默认的镜像会把filer的leveldb数据存储在根目录,删除容器就会丢失这部分数据 参见:https://github.com/chrislusf/seaweedfs/blob/master/docker/ filer.toml: [leveldb] enabled = true dir = "/data/filer/" Dockerfile: FROM chrislusf/seaweedfs COPY filer.toml /etc/seaweedfs/filer.toml 启动命令¶ docker run -dit --name weedfs --restart=always --user nobody -v /data/weedfs:/data myweed -log_dir=/data/logs/ server -dir /data -filer=true -filer.disableDirListing -volume.publicUrl=weedfs.py3.io docker network connect useweed weedfs --alias weedfs 建议在测试的时候不要用-filer.disableDirListing选项,可以列目录来看看到底上传到哪了:curl -H "Accept: application/json" "http://weedfs:8888/my_images/?pretty=y" 另外注意启动前创建文件夹和配置权限:(不要以为人家会给你创建目录) mkdir -p /data/weedfs/logs/ mkdir -p /data/weedfs/filer/ sudo chown -R nobody /data/weedfs B服务器的实现¶ TARGET_SERVER = "http://images.example.com/" WEEDFS_FILER_ENDPOINT = "http://nginx/upload_images/" from flask import Flask, Response import requests import io sess = requests.session() app = Flask(__name__) @app.route("/my_images/<name>") def handler(name): x = sess.get(TARGET_SERVER+name) sess.post(WEEDFS_FILER_ENDPOINT, files=[('filename', (name, io.BytesIO(x.content)))]) return Response(x.content, mimetype="image/jpeg") 顺便附上PYTHON库PYSEAWEED的使用¶ pip install pyseaweed 如果服务器启动的时候配置的publicUrl以https://开头,这个pyseaweed库是有问题的,需要手动修几处url构造的地方 publicurl = "http://localhost:8080/" from pyseaweed import WeedFS w = WeedFS("localhost", 9333, use_session=True) # 上传 也支持传入流 fid = w.upload_file(filename) # 下载 得到对象字节 data = w.conn._conn.get(publicurl+fid).content PROXY_PASS 动态代理¶ 效果:访问/www.example.com/ 反向代理到http://www.example.com,并支持一次跳转 location ~ ^/(.*)$ { proxy_pass http://$1; proxy_intercept_errors on; error_page 301 302 307 = @handle_redirect; } location @handle_redirect { set $saved_redirect_location '$upstream_http_location'; proxy_pass $saved_redirect_location; } -------------------------------------------------------------------------------- NGINX隐藏SERVER头 简单方式¶ 参考: https://serverfault.com/questions/214242/can-i-hide-all-server-os-info apt install -y nginx-extras 配置中添加: header_filter_by_lua 'ngx.header["server"] = nil'; -------------------------------------------------------------------------------- 使用阿里云函数计算定时更新HTTPS证书¶ 为了减少对vps的依赖,逐步将一些在服务器上跑的任务迁移到更加可靠的函数计算 这不是一个详细的教程,你还需要自行探索研究 入口¶ https://fc.console.aliyun.com 关键词: 教程 定价 128MB是免费的 定时触发器 日志服务 代码框架¶ Python3 先本地git clone --depth 1 https://github.com/Neilpang/acme.sh,再创建个index.py 把代码文件夹上传上去 网页上在线编辑index.py不会丢失acme.sh文件夹(只会改动index.py),代码改动后就能直接运行看到结果(实时输出需要去日志服务搜索),还是挺好用的 使用这个代码需要先创建一个可以访问OSS的AccessKey,填入oss2.Auth部分——将生成的https证书和私钥存储到OSS,将Key硬编码到代码中不是一个好习惯,这里就简单粗暴实现了 域名验证方式用的是challenge-alias的dns验证,需要将_acme-challenge.py3.io设置CNAME到_acme-challenge.chenyuan.me。 如果你还需要更多的子域名如*.subdomain.py3.io,那也要把_acme-challenge.subdomain.py3.io设置CNAME到_acme-challenge.chenyuan.me 用的是cloudflare的API,需要提供CF_Key和CF_Email,你也可以使用更多的API 定时器设置十五天执行一次,cron表达式为:0 0 0 1,15 * * 你需要替换下面代码的REGION OSS地域, AK, SK 可以访问OSS的密钥, OSSNAME 使用的OSS名称, CF_Key cloudflare的API Key, CF_Email cloudflare的用户名邮箱, chenyuan.me 在cloudflare上托管的域名, py3io_ATxx申请得到的证书的名称 加入随机字符串避免被猜到, ["py3.io", "*.py3.io"] 申请的域名列表 # -*- coding: utf-8 -*- import os import logging import random import os import oss2 import io import time import string import json logger = logging.getLogger() endpoint = 'http://oss-cn-REGION-internal.aliyuncs.com' auth = oss2.Auth('AK', 'SK') bucket = oss2.Bucket(auth, endpoint, 'OSSNAME') def getcert(name, domains): global logger try: try: lasttime = bucket.get_object_meta(name+".crt").last_modified if time.time() - lasttime <= 86400 * 60: # do not recreate cert for 60 days logger.info('Skip cert for '+name) return except: pass logger.info('Getting cert for '+name) domain_text = "-d '" + "' -d '".join(domains) + "'" cmd = "CF_Key=xxx CF_Email=xxx@yyy.com ./acme.sh/acme.sh --issue --dns dns_cf "+domain_text+" --dnssleep 5 --fullchain-file /tmp/"+name+".crt --key-file /tmp/"+name+".key -f " if name != "chenyuan.me": cmd += "--challenge-alias chenyuan.me" print("acme.sh --issue"+cmd.split("--issue")[1]) assert os.system(cmd)==0, "get cert failed" bucket.put_object_from_file(name+".crt", "/tmp/"+name+".crt") bucket.put_object_from_file(name+".key", "/tmp/"+name+".key") logger.info('Done for '+name) except Exception as e: logger.exception("exception happend: "+ name) def handler(event, context): getcert("py3io_ATxx", ["py3.io", "*.py3.io"]) return 'ok' 更多说明¶ 取得一个域名的证书大约需要1~2分钟,由于函数计算允许的最长超时是600秒,还有考虑网络因素(毕竟cloudflare和let’s encrypt都在国外), 是有可能失败的 我采取的策略就很简单粗暴 每15天执行一遍,一个域名失败了不影响其他域名的尝试,60天内成功了的域名不会反复申请,总会成功的 安全性:为了便于将证书部署到web服务器,OSS仓库是设置成公开读的,这样就可能泄露私钥文件(攻击者知道OSS名称,猜到文件名称),你可以用Referer限制来增加一点安全性 WEB服务器上的部署¶ 也是写一个定时任务咯 0 0 0 3,17 * *,每个月3号和17号用curl获取一下最新的证书 如果nginx的配置原先就是错的,不会尝试更新证书 如果更新证书后nginx无法启动(比如无法连上阿里云下载的文件为空或404),会回滚这个改动,保证nginx仍然可以启动 你需要替换下面代码的NAME, OSSNAME, REGION 同上, Referer_STRING 在OSS设置的只允许这个Referer_STRING访问 不允许Referer为空 增加安全性 #!/bin/bash set -ex export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin cd /var/www NAME="py3io_ATxx" curl -o ${NAME}.crt.new https://OSSNAME.oss-cn-REGION.aliyuncs.com/${NAME}.crt -H "Referer: Referer_STRING" curl -o ${NAME}.key.new https://OSSNAME.oss-cn-REGION.aliyuncs.com/${NAME}.key -H "Referer: Referer_STRING" nginx -s reload mv ${NAME}.crt ${NAME}.crt.old mv ${NAME}.key ${NAME}.key.old mv ${NAME}.crt.new ${NAME}.crt mv ${NAME}.key.new ${NAME}.key nginx -s reload || (mv ${NAME}.crt.old ${NAME}.crt; mv ${NAME}.key.old ${NAME}.key) -------------------------------------------------------------------------------- 使用NFS存储NGINX日志¶ 考虑一个不稳定的存储介质 如树莓派,想简单地把日志存储到其他服务器上 由于nfs可能由于网络hang,而Nginx在无法写日志的时候也无法提供web访问, 所以我的做法是先写到本地,每个小时将新的log追加到nfs同名.1文件里 用到的:nfs,Nginx SIGUSR1信号,定时任务 服务端的nfs镜像: https://hub.docker.com/r/itsthenetwork/nfs-server-alpine/ docker run --restart=always -d --name nfs -v /data:/nfsshare --privileged --net=host -e SHARED_DIRECTORY=/nfsshare itsthenetwork/nfs-server-alpine 客户端(web服务器): mkdir /nfs mount SERVER_IP:/ /nfs collectlog.sh写到/nfs里,如果nfs发生了hang,脚本也不会执行 #!/bin/bash export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin cd /var/log/nginx for i in *.log; do mv $i ${i}.1; done kill -USR1 `cat /var/run/nginx.pid` sleep 1 for i in *.log.1; do cat $i >> /nfs/$i done cron加入:每小时写入一次 0 * * * * /nfs/collectlog.sh -------------------------------------------------------------------------------- 使用OPENRESTY LUA编程实现HOOK跳转¶ 需求:有多个网站用户访问之前需要带上authtoken,没有这个Cookie则先跳转到登录界面 使用openresty来方便地写Lua: 安装参考 https://openresty.org/cn/linux-packages.html sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add - echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" \ | sudo tee /etc/apt/sources.list.d/openresty.list sudo apt-get update sudo apt-get -y install openresty 可能你会喜欢原来的nginx的目录设置,做个软链接呗: ln -s /usr/local/openresty/nginx/logs /var/log/nginx alias nginx=openresty 快速入门: https://openresty.org/cn/getting-started.html 就是content_by_lua_block里面直接写lua代码即可 http { server { listen 8080; location / { default_type text/html; content_by_lua_block { ngx.say("<p>hello, world</p>") } } } } 想知道ngx有哪些方法,看这个文档: https://github.com/openresty/lua-nginx-module#ngxarg 例如获取http GET的a参数:ngx.var.arg_a, 请求的Host参数:ngx.var.http_host 获取Cookie: 使用https://github.com/cloudflare/lua-resty-cookie 先执行:wget -O /etc/openresty/cookie.lua https://github.com/cloudflare/lua-resty-cookie/raw/master/lib/resty/cookie.lua 在http中加入: lua_package_path "/etc/openresty/?.lua;;"; local ck = require "cookie" local cookie, err = ck:new() if not cookie then ngx.log(ngx.ERR, err) return end #然后即可使用cookie:get("authtoken") 想使用rewrite_by_lua_file则需要把文件放在/usr/local/openresty/nginx 结束当前脚本继续后续请求处理 用ngx.exit(0) 结束整个请求 用ngx.exit(200) 跳转用 ngx.redirect("https://py3.io") Lua的三目运算: a and b or c -------------------------------------------------------------------------------- 不同子域名反代到不同端口¶ 你可以复制粘贴多个server块,但使用map是一个更优雅的方案 http { map $subdomain $subdomain_port { subdomain1 12345; subdomain2 54321; default 1; } server { listen 80; server_name ~^(?P<subdomain>.+?)\.2020\.actf\.lol$; location / { proxy_pass http://127.0.0.1:$subdomain_port; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } } NGINX配置文件格式化¶ 直接用vi改了配置文件后,很容易不注意缩进,有没有一个自动prettify的工具呢 还真有: https://github.com/1connect/nginx-config-formatter wget https://raw.githubusercontent.com/1connect/nginx-config-formatter/master/nginxfmt.py python3 nginxfmt.py /etc/nginx/nginx.conf 浙ICP备15043819号-2 浙公网安备 33010602007826号 Made with Material for MkDocs