搭建btcloud宝塔云端

btcloud是一款开源的宝塔云端程序,简单说就是:有了btcloud,你安装宝塔,安装宝塔插件(免费和付费),都不再需要跟宝塔官方通信了,btcloud接管了所有的官方通信,可以把btcloud理解成宝塔server端,你在其它vps上安装宝塔,就都是与此btcloud通信,使用此btcloud脚本。

Github:https://github.com/flucont/btcloud

那么,通过btcloud为什么能够安装宝塔的企业收费插件呢?

那是因为btcloud后台绑定宝塔企业账号后,可以将所有插件都缓存到本地。所以要搭建btcloud,你还需要有一个宝塔企业账号。当然也可以用别人搭建好的btcloud来绑定(https://install.baota.sbs/),实现循环套娃;也有人说可以用bt.sy来套娃,不过我没有试验过。

以下记录搭建btcloud的过程。

一、用一台小鸡来搭建btcloud

配置要求可以参看GitHub说明,下载最新release包到对应目录,解压,设置网站运行目录为public,设置伪静态为ThinkPHP,访问网站,会自动跳转到安装页面,根据提示安装完成。

如果是用惯了宝塔的小白,不会上述过程,其实你也可以先在小鸡上安装宝塔官方版本或者aapanel,通过aapanel来配置环境部署btcloud,你也可以绑定一个域名,比如bt.168itw.com来访问btcloud程序。

二、登录btcloud后台(比如 bt.168itw.com/admin),执行相关操作

  1. 系统设置 – 替换与清理工具,复制相关命令,在安装btcloud的vps的ssh客户端上执行;
  2. 系统设置 – 面板接口设置,这里就需要设置绑定你的宝塔企业账号,用于btcloud缓存插件,如果没有企业账号,可以选择对接第三方云端(比如https://install.baota.sbs/等),测试通过后,保存;
  3. 系统设置 – 自动更新插件设置,先设置需要下载的插件范围,然后复制相关命令,去安装btcloud的vps ssh执行,缓存宝塔插件到本地,后期可以通过添加到crontab命令来自动同步插件;
  4. 其它设置:系统设置 – 软件版本设置,来设置白名单,以及是否开启脚本展示页面等。

至此,btcloud就安装完成了,访问/download页面,查看自己的宝塔装脚本。现在你就可以在任意vps上运行该脚本来安装宝塔,并且安装付费的插件了。

daemon.json配置docker容器日志大小及错误排查

docker日志目录:/var/lib/docker/containers/<容器id>/

docker容器的运行日志,如果不加以限制,会越来越大,占用非常大的磁盘空间。可以通过daemon.json配置docker日志文件大小,全局有效。

    docker安装后默认没有daemon.json这个配置文件,需要进行手动创建,docker不管是在哪个平台以何种方式启动, 默认都会来这里读取配置,使用户可以统一管理不同系统下的 docker daemon 配置。

    如果在daemon.json文件中进行配置,需要docker版本高于1.12,配置文件的默认径为:/etc/docker/daemon.json      

    该文件作为 Docker Engine 的配置管理文件, 里面几乎涵盖了所有 docker 命令行启动可以配置的参数。

如果没有daemon.json,新建一个,添加以下内容:

{
"exec-opts": [""],
"log-driver":"json-file",
 "log-opts": {
   "max-size": "300m",
   "max-file": "1"
 }
}

然后重启docker守护进程:

systemctl daemon-reload
systemctl restart docker

如果docker无法启动报错,使用dockerd查看输出错误信息:

dockerd

在网上看到docker无法启动后,systemctl status docker.service、cat /lib/systemd/system/docker.service等等,各种排查,其实都不能有效的找出错误原因,只有dockerd才是输出有效的错误信息。

另外需要注意,改动了daemon.json后,都一定是要运行systemctl daemon-reload和systemctl restart docker来重启docker。

APISIX网关部署使用教程

APISIX是一个具有动态、实时、高性能等特点的云原生 API 网关。你可以使用 APISIX 网关作为所有业务的流量入口,它提供了动态路由、动态上游、动态证书、A/B 测试、灰度发布(金丝雀发布)、蓝绿部署、限速、防攻击、收集指标、监控报警、可观测、服务治理等功能。

安装APISIX

部署apisix最简单的方法就是docker部署,直接使用官方的example配置。

git clone https://github.com/apache/apisix-docker.git
cd apisix-docker/example

example下的docker-compose.yml和docker-compose-arm64.yml分别对应的是X86和ARM服务器。

查看yml文件会发现,会启动了多个docker服务:

  • apisix:主程序,api网关;
  • etcd:APISIX 使用 etcd 作为配置中心进行保存和同步配置;
  • prometheus:开源的监控程序;
  • grafana:开源的看板程序;

web1和web2是测试程序,可以直接去掉。

另外,如果我们要使用apisix的UI控制面板,可以在docker-compose.yml中再加一个apisix-dashboard的docker服务:

  apisix-dashboard:
    image: apache/apisix-dashboard:3.0.1-alpine
    restart: always
    volumes:
    - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
    ports:
    - "9000:9000"
    networks:
      apisix:

最终的docker-compose.yml文件为:

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

version: "3"

services:
  apisix-dashboard:
    image: apache/apisix-dashboard:3.0.1-alpine
    restart: always
    volumes:
    - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
    ports:
    - "9000:9000"
    networks:
      apisix:

  apisix:
    image: apache/apisix:${APISIX_IMAGE_TAG:-3.6.0-debian}
    restart: always
    volumes:
      - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    depends_on:
      - etcd
    ##network_mode: host
    ports:
      - "9180:9180/tcp"
      - "9080:9080/tcp"
      - "9091:9091/tcp"
      - "9443:9443/tcp"
      - "9092:9092/tcp"
    networks:
      apisix:

  etcd:
    image: bitnami/etcd:3.4.15
    restart: always
    volumes:
      - etcd_data:/bitnami/etcd
    environment:
      ETCD_ENABLE_V2: "true"
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_ADVERTISE_CLIENT_URLS: "http://etcd:2379"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
    ports:
      - "2379:2379/tcp"
    networks:
      apisix:

  prometheus:
    image: prom/prometheus:v2.25.0
    restart: always
    volumes:
      - ./prometheus_conf/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      apisix:

  grafana:
    image: grafana/grafana:7.3.7
    restart: always
    ports:
      - "3000:3000"
    volumes:
      - "./grafana_conf/provisioning:/etc/grafana/provisioning"
      - "./grafana_conf/dashboards:/var/lib/grafana/dashboards"
      - "./grafana_conf/config/grafana.ini:/etc/grafana/grafana.ini"
    networks:
      apisix:

networks:
  apisix:
    driver: bridge

volumes:
  etcd_data:
    driver: local

通过修改本地example/dashboard_conf/conf.yaml 文件,来修改控制面板的配置。需要修改users中的用户名和密码,用于登录控制面板。

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

conf:
  listen:
    host: 0.0.0.0     # `manager api` listening ip or host name
    port: 9000          # `manager api` listening port
  allow_list:           # If we don't set any IP list, then any IP access is allowed by default.
    - 0.0.0.0/0
  etcd:
    endpoints:          # supports defining multiple etcd host addresses for an etcd cluster
      - "http://etcd:2379"
                          # yamllint disable rule:comments-indentation
                          # etcd basic auth info
    # username: "root"    # ignore etcd username if not enable etcd auth
    # password: "123456"  # ignore etcd password if not enable etcd auth
    mtls:
      key_file: ""          # Path of your self-signed client side key
      cert_file: ""         # Path of your self-signed client side cert
      ca_file: ""           # Path of your self-signed ca cert, the CA is used to sign callers' certificates
    # prefix: /apisix     # apisix config's prefix in etcd, /apisix by default
  log:
    error_log:
      level: warn       # supports levels, lower to higher: debug, info, warn, error, panic, fatal
      file_path:
        logs/error.log  # supports relative path, absolute path, standard output
                        # such as: logs/error.log, /tmp/logs/error.log, /dev/stdout, /dev/stderr
    access_log:
      file_path:
        logs/access.log  # supports relative path, absolute path, standard output
                         # such as: logs/access.log, /tmp/logs/access.log, /dev/stdout, /dev/stderr
                         # log example: 2020-12-09T16:38:09.039+0800	INFO	filter/logging.go:46	/apisix/admin/routes/r1	{"status": 401, "host": "127.0.0.1:9000", "query": "asdfsafd=adf&a=a", "requestId": "3d50ecb8-758c-46d1-af5b-cd9d1c820156", "latency": 0, "remoteIP": "127.0.0.1", "method": "PUT", "errs": []}
  security:
      # access_control_allow_origin: "http://httpbin.org"
      # access_control_allow_credentials: true          # support using custom cors configration
      # access_control_allow_headers: "Authorization"
      # access_control-allow_methods: "*"
      # x_frame_options: "deny"
      content_security_policy: "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-src *"  # You can set frame-src to provide content for your grafana panel.

authentication:
  secret:
    secret              # secret for jwt token generation.
                        # NOTE: Highly recommended to modify this value to protect `manager api`.
                        # if it's default value, when `manager api` start, it will generate a random string to replace it.
  expire_time: 3600     # jwt token expire time, in second
  users:                # yamllint enable rule:comments-indentation
    - username: username   # username and password for login `manager api`
      password: password

plugins:                          # plugin list (sorted in alphabetical order)
  - api-breaker
  - authz-keycloak
  - basic-auth
  - batch-requests
  - consumer-restriction
  - cors
  # - dubbo-proxy
  - echo
  # - error-log-logger
  # - example-plugin
  - fault-injection
  - grpc-transcode
  - hmac-auth
  - http-logger
  - ip-restriction
  - jwt-auth
  - kafka-logger
  - key-auth
  - limit-conn
  - limit-count
  - limit-req
  # - log-rotate
  # - node-status
  - openid-connect
  - prometheus
  - proxy-cache
  - proxy-mirror
  - proxy-rewrite
  - redirect
  - referer-restriction
  - request-id
  - request-validation
  - response-rewrite
  - serverless-post-function
  - serverless-pre-function
  # - skywalking
  - sls-logger
  - syslog
  - tcp-logger
  - udp-logger
  - uri-blocker
  - wolf-rbac
  - zipkin
  - server-info
  - traffic-split

运行docker compose启动docker:

docker-compose -p docker-apisix up -d

配置APISIX

通过修改本地 ./conf/config.yaml 文件,完成对 APISIX 服务本身的基本配置。建议修改 Admin API 的key,保护 APISIX 的安全。同时可以限制IP访问API,增加安全性:

deployment:
  admin:
    allow_admin:               # https://nginx.org/en/docs/http/ngx_http_access_module.html#allow
      - 127.0.0.0/24              # We need to restrict ip access rules for security. 0.0.0.0/0 is for test.
      - 本机IP

    admin_key:
      - name: "admin"
        key: newpassword
        role: admin                 # admin: manage all configuration data

上述限制IP的策略,主要是考虑apisix-dashboard控制面板来访问api,其它应用场合根据实际情况修改。

使用APISIX

访问http://ip:9000,用上述用户名和密码就可以登录API控制面板了。具体使用过程比较简单,这里不详述,只说下在使用容易踩坑的地方。

apisix最常用的就是对访问进行限速控制,主要涉及到三个插件:

  • limit-conn:并发请求数
  • limit-count:指定时间窗口内的请求数量
  • limit-req:请求速率

而限速又涉及到访客IP,只有获取到用户的真实IP才能有效地限速,所以这里就又涉及到real ip插件。

  1. APISIX官方文档中,说real IP插件需要重新编辑APISIX-Base,但实际上,现在新版本的apisix docker镜像,都已经是运行在APISIX-Base上的。
  2. APISIX传递real IP给上游,需要自行配置,plugin字段中添加如下代码:
    "real-ip": {
      "source": "http_x_forwarded_for",
      "trusted_addresses": [
        "0.0.0.0/0"
      ]
    }

source必须为http_x_forwarded_for才有效,使用官方文档中的$remote_addr、$remote_port测试都无效,这是我踩过很久的坑。

trusted_addresses为信任的回源IP,可以根据实际情况修改。比如,如果使用nginx反代了apisix网关,则trust IP是反代服务器IP:

    "real-ip": {
      "source": "http_x_forwarded_for",
      "trusted_addresses": [
        "反代服务器IP"
      ]
    }

3. 在上述3个插件的配中,key的值必须为remote_addr,才能获取到访客真实IP,使用官方文档中的http_x_real_ip、http_x_forwarded_for都无效,也不知道是哪里的问题。

4. 如果你的APISIX前面还运行了一层nginx,或者是还套了一层cloudflare(访客访问域名 – cloudflare CDN – nginx – APISIX),那么就需要递归传递用户的真实IP,特别注意的是因为apisix运行在docker,所以set_real_ip_from需要添加docker内网IP段:

docker inspect 容器id
set_real_ip_from 172.18.0.0/24

可以参考前面的文章:https://www.168itw.com/web-server/cloudflare-cdn-real-ip/
也可以参考:https://github.com/apache/apisix/discussions/4793

其它更多功能还没有测试,后期继续补充完善该教程。

使用cloudflare CDN的网站获取访客真实IP

之前有一篇文章是介绍宝塔获取cloudflare CDN访客真实IP的文章,但是那篇文章比较粗糙。下面结合cloudflare官方的说明文档,做一些补充说明。

一、CF-Connecting-IP 和 X-Forwarded-For

cloudflare将原始访问者 IP 地址显示在名为 CF-Connecting-IP 和 X-Forwarded-For 的附加 HTTP 标头中。所以你可以选择用:

real_ip_header CF-Connecting-IP; 

或者:

real_ip_header X-Forwarded-For;
real_ip_recursive on;

来获取访客真实IP。

二、ngx_http_realip_module模块

nginx服务器获取realip是依赖ngx_http_realip_module模块的,所以如果你用的是nginx,必须要编译ngx_http_realip_module模块。使用nginx -V命令查看nginx是否已经编译该模块,没有的话需要自己编译。

其它服务器参考cloudflare官方说明文档

三、set_real_ip_from的使用

如果是 set_real_ip_from 0.0.0.0/0; 则表示允许所有IP回源,会有安全隐患,我们可以设置为只允许cloudflare的IP回源:

server
{
listen 443 ssl http2;
listen [::]:80;
server_name 168itw.com;

set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;

#X-Forwarded-For和CF-Connecting-IP二选一
real_ip_header    X-Forwarded-For;
real_ip_recursive on;
#real_ip_header CF-Connecting-IP; 

cloudflare IP段:https://www.cloudflare.com/ips/

注意:添加在nginx的http{}中,则全局应用在下面的所有server中,即所有网站生效;添加在网站对应的server{}中,则只有该网站中生效。

特别注意:如果同时运行了docker,且有反代docker服务,则需要将docker内网IP段也要加到set_real_ip_from中。

查看docker容器IP:

docker inspect 容器id

添加docker内网IP段:

set_real_ip_from 172.18.0.0/24

四、多级反向代理

如果cloudflare之后还有多级反向代理,可以在cloudflare后的第一级反代只允许cf IP回源,后面的允许上一级反代IP回源。

五、开启CLOUDFLARE的回源认证

cloudflare后台 SSL/TLS – Overview:SSL/TLS encryption mode设置为Full或者Full (strict)

SSL/TLS – Origin Server 开启:Authenticated Origin Pulls

在对应主机的配置文件的server块内加入下列代码:

ssl_client_certificate /etc/nginx/certs/cloudflare.pem;
ssl_verify_client on;

cloudflare.pem文件下载地址:https://developers.cloudflare.com/ssl/origin-configuration/authenticated-origin-pull/set-up/zone-level/

继续阅读

nginx禁止IP访问目录或文件及location匹配规则

一、关于deny和allow的使用

nginx通过ngx_http_access_module模块来控制IP访问特定路径,可以放在httpserverlocation中。比如:

location / {
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 10.1.1.0/16;
    allow 2001:0db8::/32;
    deny  all;
}

nginx按顺序检查规则,直到找到第一个匹配项。注意在使用指令时,如果最后不添加deny all,则可能会允许上面列出ip之外的其他ip均可访问,因为默认是allow all的。

   deny 43.243.12.116;
   deny 43.241.242.243;
   allow all;

所以,上面例子中最后的allow all可以不用添加,因为默认是allow all的。

二、nginx location 配置

  1. 禁止访问某些后缀文件
location ~ \.(ini|conf|txt)$ {
    deny all;
}

2. 禁止访问目录或目录下文件

#禁止访问目录
location ^~ /test/ {
    deny all;
}
#禁止访问目录下文件
location ^~ /test {
    deny all;
}

3. 禁止访问某个目录下的指定文件后缀文件

# 禁止访问某个目录下的 php 后缀文件
location /directory {
    location ~ .*\.(php)?$ {
    deny all;
    }
}
# 禁止访问多个目录下的 php 后缀文件
location ~* ^/(directory1|directory2)/.*\.(php)${
    deny all;
}

location可以嵌套使用,也就是说一个location中可以继续嵌套location。

三、location匹配规则详解

= 表示精确匹配

^~ 表示uri以某个字符串开头

~ 正则匹配(区分大小写)

~* 正则匹配(不区分大小写) !~和!~*分别为区分大小写不匹配及不区分大小写不匹配的正则

/ 任何请求都会匹配

匹配优先级: ​​= > ^~ > /​​

举例:

    location ~ .*\.(json)?$ {
    allow 127.0.0.1/16;
    deny all;
    expires      -1;
    }
  1. location: 表示定义一个匹配规则的位置块。
  2. ~: 表示后面跟着的是一个正则表达式,而不是普通的字符串匹配。
  3. .*: 表示匹配任意字符(除了换行符)零次或多次。这里是匹配任意字符零次或多次,即允许路径中包含任意字符。
  4. \.: 表示匹配点(.)字符。在正则表达式中,点(.)通常表示任意字符,但在这里通过反斜杠进行转义,表示匹配实际的点字符。
  5. (json)?: 表示匹配括号内的内容零次或一次,即json可选。这里的括号用于创建一个捕获组,表示括号内的内容是一个整体,而问号表示前面的字符(这里是 (json))可选。
  6. $: 表示匹配字符串的结尾。

参考文档:

继续阅读

清理docker占用的硬盘空间

docker system 命令

docker system df命令,类似于 Linux 上的df命令,用于查看 Docker 的磁盘使用情况:

docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              147                 36                  7.204GB             3.887GB (53%)
Containers          37                  10                  104.8MB             102.6MB (97%)
Local Volumes       3                   3                   1.421GB             0B (0%)
Build Cache                                                 0B                  0B

docker system prune命令可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及 dangling 镜像(即无 tag 的镜像)。

docker system prune -a命令清理得更加彻底,可以将没有容器使用 Docker 镜像都删掉。

注意,这两个命令会把你暂时关闭的容器,以及暂时没有用到的 Docker 镜像都删掉了…所以使用之前一定要想清楚吶。

手动清理

  1. 清理无用的容器

使用命令docker ps -a列出所有容器,找出不再需要的容器,使用命令docker rm <container_id>删除它们。在删除容器之前,可以使用命令docker stop <container_id>先停止容器。

  1. 清理无用的镜像

使用命令docker images列出所有镜像,找出不再需要的镜像,使用命令docker image rm <image_id>删除它们。在删除镜像之前,可以使用命令docker stop <container_id>先停止容器。

  1. 清理无用的数据卷

使用命令docker volume ls列出所有数据卷,找出不再需要的数据卷,使用命令docker volume rm <volume_name>删除它们。在删除数据卷之前,需要先删除使用该数据卷的容器。

  1. 清理无用的网络

使用命令docker network ls列出所有网络,找出不再需要的网络,使用命令docker network rm <network_name>删除它们。在删除网络之前,需要先删除使用该网络的容器。

5. 清理Docker日志

Docker日志会占用大量空间,可以使用命令docker logs --tail 50 <container_id>来查看最近50行的日志。如果需要清理全部日志,可以使用命令truncate -s 0 /var/lib/docker/containers/*/*/*.log来清空所有日志文件。

Cloudflare Cache Rules搭配Page Rules实现灵活缓存

之前有写过Cloudflare Page Rules缓存全站的用法,但是遇到像部分页面不能缓存(类似于动态获取参数等)的时候,Page Rules设置就不够灵活了,而且cloudflare免费账户的3条Page Rules规则,明显不够用,我们就需要配合Cache Rules来使用。

Cache Rules比Page Rules的设置更加灵活方便,而且免费账户支持10条规则。

使用Cache Rules之前,需要先搞清楚它与Page Rules之间的区别:

  1. Cache Rules的优先级高于Page Rules。也就是说,如果Cache Rules中的规则与Page Rules冲突,Cache Rules规则会覆盖Page Rules规则。这就非常适合上面说的情况,用Cache Rules来排除某些不需要缓存的页面。
  2. Cache Rules规则从上往下,权重是递增的。也就是说,如果规则有冲突,下面的规则会覆盖上面的规则。

详细说明参考Cloudflare官方:https://developers.cloudflare.com/cache/how-to/cache-rules/

下面以wordpress为例,来设置Cloudflare Cache Rules搭配Page Rules实现灵活缓存规则。相比之前的设置,做了进一步的优化。

Page Rules规则

  1. URL: www.168itw.com/wp-admin*
    Cache Level: Bypass
    Disable Performance
  2. URL: www.168itw.com/*php*
    Cache Level: Bypass
    Disable Performance
  3. URL: www.168itw.com/*
    Cache Level: Cache Everything
    Edge Cache TTL: a day

规则1不缓存wordpress后台。

规则2不缓存特殊动态页面,比如动态支付页面,动态API页面,这就需要根据自己的页面结构来确定URL特性;当然这里也包括了wordpress后台登录页面wp-login.php。

规则3缓存全站,包括首页,缓存时间为1天。

Cache Rules规则

以影视站点为例,我需要用nginx对电视剧频道的视频鉴权防盗链(Nginx secure_link模块给网站添加防盗链),所以该频道页面需要动态生成鉴权token,因此不能按照Page Rules规则来缓存1天。

  1. Rule name: tv channels cache rule
    When incoming requests match…
    URI Path – Contains – /tv And
    Hostname – equals – www.168itw.com
    Cache status
    Bypass cache
    Browser TTL
    Respect origin
  2. Rule name: css & js & woff & img cache rule
    When incoming requests match…
(http.request.uri contains ".css") or (http.request.uri contains ".js") or (http.request.uri contains ".woff") or (http.request.uri contains ".jpg") or (http.request.uri contains ".png") or (http.request.uri contains ".svg") or (http.request.uri contains ".gif") or (http.request.uri contains ".bmp") or (http.request.uri contains ".ico")

Cache status
Eligible for cache
Edge TTL
7 days
Browser TTL
Override origin – 1 day

这里需要说明下:

规则1中Browser TTL设置为Respect origin,即浏览器缓存,按照默认的浏览器缓存设置来,默认设置在cloudflare的Caching – Configuration中,默认是30minutes,你也可以根据需要来修改。因为我的nginx鉴权设定为3小时,所以用户浏览器缓存30分钟是完全没问题的。

规则2是缓存css、js、woff字体、jpg等图片,因为规则1排除了tv目录下所有页面的缓存,但是这些页面上的静态资源是可以缓存的;当然,该条规则也会覆盖掉Page Rules中对于静态规则的缓存设置,因为它的优先级比较高。

nginx使用replace-filter-nginx-module模块正则替换

nginx反代,要实现内容替换,sub_filter功能有限,而且不支持正则匹配;本来开始是使用ngx_http_substitutions_filter,发现怎么都不起作用,也不知道是哪里问题。后来找到一个更加强大的替换模块:replace-filter-nginx-module

GitHub地址:https://github.com/openresty/replace-filter-nginx-module

安装此模块需要先安装sregex运行库。

cd /www/server/nginx/src
git clone https://github.com/agentzh/sregex
cd sregex
make
make install

安装 replace-filter-nginx-module

cd /www/server/nginx/src
git clone https://github.com/agentzh/replace-filter-nginx-module

nginx -V查看,添加replace-filter-nginx-module编译:

./configure --user=www --group=www --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --add-module=/www/server/nginx/src/ngx_http_substitutions_filter_module-master --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module --with-http_secure_link_module --add-module=/www/server/nginx/src/replace-filter-nginx-module

安装之后,替换nginx

make
cp /www/server/nginx/sbin/nginx /www/server/nginx/sbin/nginx.bak
nginx -s stop
cp /www/server/nginx/src/objs/nginx /www/server/nginx/sbin/nginx
service nginx restart

重启nginx的时候发现报错了:

error while loading shared libraries: libsregex.so.0: cannot open shared object file: No such file or directory

查看时哪里的问题:

ldd $(which /www/server/nginx/sbin/nginx)

发现 libsregex.so.0 => not found,nginx只从/lib/x86_64-linux-gn路径下寻找,那么我们将类库直接复制过去就行:

cp /www/server/nginx/src/sregex/libsregex.so.0 /lib/x86_64-linux-gnu

再次重启nginx,就没问题了:

service nginx restart

查看nginx -V,确认模块安装成功。

关于replace-filter-nginx-module正则替换规则,可以参看GitHub说明。

Nginx secure_link模块给网站添加防盗链

网站上的一些静态资源文件,比如图片、pdf、压缩文件、m3u8等视频文件,经常会被盗链,之前我都是用referrer来防盗链,但是referrer太容易伪造了。后来nginx的secure_link可以很好的解决这个问题。

该模块有三个指令,分别为:secure_link、secure_link_md5、secure_link_secret,使用方法有两种:

  1. secure_link + secure_link_secret(v0.7.18以后);
  2. secure_link + secure_link_md5(v0.8.5以后,其实就是用来替代第一种的)。

后面的部署过程我们都是采用方法2。

secure_link + secure_link_md5基本原理

  1. 把一些参数以及过期时间按你想要的顺序拼成一个字符串,然后对它做md5计算,然后把这个md5和过期时间以参数的方式附加到链接后面。
  2. 在nginx中我们配置同样的参数串顺序,nginx会按我们给出的参数串计算出它的md5值,然后把它计算得到的md5值与链接中传过来的md5值作对比,如果两个值不相同,则会把变量$secure_link设置为空字符串。
  3. 如果md5值相同,nginx还会继续对比过期时间,如果链接已经过期(其实就是当前时间戳大于链接中传过来的时间戳),那么它会把$secure_link的值置为”0″,否则为”1″。
  4. 综上,我们只需要用if检测$secure_link的值,如果为空,则说明这个链接不是合法链接,如果不为空,则继续用if检测它的值是否为”0″,,只要为空或为0,那么我们就可以判断它不是合法请求,就可以用return 403或者rewrite的方式去处理这种不合法请求;

以下记录整个过程。

1、编译secure_link模块

我用的是宝塔,默认是没有编译secure_link,通过查看nginx -V确认下:

/www/server/nginx/sbin/nginx -V
cd /www/server/nginx/src/

在最后面添加–with-http_secure_link_module,编译:

./configure  --user=www --group=www --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module --with-http_secure_link_module
make

备份nginx:

cp /www/server/nginx/sbin/nginx /www/server/nginx/sbin/nginx.bak

停止nginx:

nginx -s stop

继续:

cp /www/server/nginx/src/objs/nginx /www/server/nginx/sbin/nginx

然后启动nginx

systemctl restart nginx

查看nginx -V是否成功编译secure_link模块:

/www/server/nginx/sbin/nginx -V

2、Nginx配置

location /yourpath/ {
    secure_link $arg_md5,$arg_expires; #这里配置了2个参数一个是arg_md5,一个是arg_expires
    secure_link_md5 "123456$uri$arg_expires"; #123456为自定义的加密串(这里的md5加密顺序要和程序生成的加密顺序保持一致)   

    if ($secure_link = "") {
        return 403; #资源不存在或哈希比对失败
    }

    if ($secure_link = "0") {
        return 410; #时间戳过期 
    }
}

3、配置网站PHP

<?php
$secret = '123456';

####下载文件,切记路径带上/
$path = "/file/168itw.zip";

####下载到期时间,time是当前时间,$validtime表示有效期,也就是说从现在到300秒之内文件不过期
$validtime = 300;
$expire = time() + $validtime;

####用文件路径、密钥、过期时间生成加密串(注意这里的md5加密顺序要和nginx配置文件中的顺序保持一致)
$md5 = base64_encode(md5($secret . $path . $expire, true));
$md5 = strtr($md5, '+/', '-_');
$md5 = str_replace('=', '', $md5);

####加密后的下载地址
$uri = $path . '?md5=' . $md5 . '&expires=' . $expire;

####安全下载链接可以直接echo输出
$uri = "https://www.168itw.com" . $uri;
?>

输出上述文件链接:

<?php echo $uri; ?>

如果使用的是wordpress,需要在文章post中添加防盗链文件,可以安装Insert PHP Code Snippet插件,这样就可以在任意文章中任何位置插入PHP代码。

参考文章:https://www.xiebruce.top/1799.html

RealVNC: VNC Server has no authentication schemes configured错误

RealVNC连接远程server端的时候,提示:VNC Server has no authentication schemes configured. 错误。

解决方法:

  1. 在server端打开Powershell
  2. 输入以下命令:
New-ItemProperty -Path "HKLM:\Software\RealVNC\vncserver" -Name "Authentication" -Value "VncAuth"
& "C:\Program Files\RealVNC\VNC Server\vncpasswd.exe" -service

按提示输入密码。

重新连接realvnc,输入刚才的密码即可成功连接。