MoreRSS

site iconXingPing | 邢平修改

Python程序员,enhanced-FaaS-in-China作者。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

XingPing | 邢平的 RSS 预览

让traefik代替你的 waf(使用CrowdSec)+ nginx + acme.sh + mtls-auth

2025-07-16 00:00:00

traefik 可以帮你:

  1. 自动续证书
  2. 反代(自动处理 ws、tls 证书、反代地址、压缩 etc.)
  3. 使用插件代替 waf
  4. 负载均衡(可以使用多个后端、k8s)
  5. 支持 mTLS 认证(如果你使用的是 Cloudflare 的 CDN)

前言

本文是对traefik的一个简单介绍,主要介绍如何使用 traefik 来代替 waf(使用 CrowdSec)、nginx、acme.sh、mtls-auth 等。

traefik会是你服务器的入口,所有的请求都会先经过 traefik,然后再转发到后端服务。

后端服务也不用配置绑定的端口和ip了(例如docker.port: 127.0.0.1:8080:8080,然后nginx反代,每个服务都要记住端口很麻烦),traefik 会自动处理。

info

主要贴出配置,注意多看注释

IMPORTANT

CrowdSec 的工作原理之后会说

info

简单说一下 mtls 的好处

  1. 如果其他人通过你的域名扫描全网 ip,没有 mtls 很容易就扫到你的服务器 ip 了,然后被定点攻击
  2. 如果你使用了 mtls 认证,其他人就算扫到你的 ip 也无法访问你的服务,除非他有 cf 的客户端证书,这个只有 cf 有私钥,无法伪造

traefik 配置

此项配置了之后可以

  1. 自动帮你续证书
  2. 如果你用的是 cf 的 cdn,还可以自动 mtls 认证。
  3. 使用 CrowdSec 作为 WAF(之后再配置 CrowdSec)
  4. 扫 443 和 80 端口的请求直接丢弃
配置结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
traefik/
├── acme.json
├── docker-compose.yml
├── cf-cert/
│ └── cloudflare-ca.pem
├── dynamic_conf/
│ ├── ban.html
│ ├── cloudflare-mtls.yml
│ ├── compressor.yml
│ ├── crowdsec-middleware.yml
│ └── drop-ip-access.yml
└── logs/
└── traefik.log

ERROR

ban.html 我就不贴了,需要的自己 ai 写一个

IMPORTANT

  1. 如果要自动帮你续证书,记得acme.json的权限要设置为600,否则 traefik 无法写入证书。
  2. 如果你使用的是 cf 的 cdn,记得在添加你的 cf 证书。到这里下载证书。
  3. 记得事先创建traefik-net网络,或者在docker-compose.yml中注释掉网络部分。
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
services:
traefik:
image: traefik:latest # 建议使用明确的版本号,而不是 latest。现在用的是 v3
container_name: traefik
restart: unless-stopped

# --- 静态配置:通过 command 而不是文件 ---
command:
- "--entrypoints.websecure.http.middlewares=crowdsec-bouncer@file,global-compressor@file"
# --- CrowdSec 插件配置 ---
- "--experimental.plugins.crowdsec-bouncer-traefik-plugin.modulename=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
- "--experimental.plugins.crowdsec-bouncer-traefik-plugin.version=v1.4.4"
# --- API 和仪表盘 ---
# - "--api.dashboard=true" # 启用仪表盘
# # 警告:下面的 insecure=true 仅用于开发环境,方便通过 8080 端口访问。生产环境请务必通过安全路由暴露。
# - "--api.insecure=true"

# --- 入口点定义 ---
- "--entrypoints.web.address=:80" # 定义 HTTP 入口点,监听80端口
- "--entrypoints.websecure.address=:443" # 定义 HTTPS 入口点,监听443端口

# --- Cloudflare IPs ---
- "--entrypoints.web.forwardedheaders.trustedips=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22"

# --- Docker Provider 配置 ---
- "--providers.docker=true" # 启用 Docker 服务发现
- "--providers.docker.exposedbydefault=false" # 默认不暴露任何容器,更安全
- "--providers.docker.network=traefik-net" # 指定Traefik监听哪个网络


#配置log
- "--log.level=DEBUG" # 设置日志级别为DEBUG
- "--log.filePath=/var/log/traefik.log" # 设置日志文件路径
# - "--log.format=json" # 设置日志格式为JSON,便于后续处理

# --- 文件 Provider 配置 ---
- "--providers.file=true" # 启用文件提供者
- "--providers.file.directory=/etc/traefik/dynamic_conf" # 指定动态配置文件目录
- "--providers.file.watch=true" # 启用动态配置文件监控

- "--accesslog=true" # 启用访问日志
- "--accesslog.format=json" # 建议使用json格式,便于后续处理

# --- Let's Encrypt (SSL证书) 配置 ---
# 暂时注释掉,在您配置好域名后可以启用
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=xxx"
- "--certificatesresolvers.myresolver.acme.storage=/etc/traefik/acme.json"
# 注意:请确保acme.json文件权限为600,Traefik才能写入证书




# --- 端口映射 ---
ports:
- "80:80"
- "443:443"
# - "8080:8080" # 暴露仪表盘的8080端口(仅开发)

# --- 挂载卷 ---
volumes:
# 挂载Docker socket,让Traefik可以监听到容器的创建和销毁
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# 挂载acme.json文件,用于持久化SSL证书
- "./acme.json:/etc/traefik/acme.json"
# 挂载动态配置文件目录
- "./dynamic_conf:/etc/traefik/dynamic_conf:ro"
# 挂载日志目录
- "./logs:/var/log:rw"
- "./cf-cert:/etc/traefik/cf-cert:ro"

# --- 网络 ---
networks:
- traefik-net

networks:
traefik-net:
name: traefik-net
external: true
cloudflare-mtls.yml
1
2
3
4
5
6
7
8
tls:
options: # 给这个 TLS 选项起一个名字
cloudflare-mtls:
minVersion: VersionTLS12
clientAuth:
caFiles: - /etc/traefik/cf-cert/cloudflare-ca.pem
clientAuthType: "RequireAndVerifyClientCert"

compressor.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# traefik/dynamic_conf/middlewares.yml
http:
middlewares:
# 定义一个全局可用的压缩中间件,我们给它起个名字叫 'global-compressor'
global-compressor:
compress:
# 在这里可以设置更详细的参数,进行精细化控制

# 排除不需要压缩的内容类型(例如图片,因为它们已经被压缩过了)
excludedContentTypes:
- "image/png"
- "image/jpeg"
- "image/gif"
- "application/pdf"

# 设置压缩算法,默认是gzip
# 也可以使用 'br' (Brotli) 或者 'deflate'
# 但注意,Brotli在某些浏览器上支持不如gzip
# algorithm: "gzip" # 默认是gzip,通常不需要显式设置
# 设置压缩级别,范围是1到9,数字越大压缩率越高,但CPU消耗也越大

# 设置一个最小响应体大小,小于这个大小的响应不进行压缩 (避免浪费CPU)
minResponseBodyBytes: 1024 # 即只压缩大于1KB的响应
crowdsec-middleware.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
http:
middlewares:
crowdsec-bouncer:
plugin:
crowdsec-bouncer-traefik-plugin:
CrowdsecLapiKey: "" #填自己的
Enabled: "true"
crowdsecMode: "stream"
# logLevel: "DEBUG"
banHTMLFilePath: "/etc/traefik/dynamic_conf/ban.html" #自己生成
forwardedHeadersCustomName: "CF-Connecting-IP"
forwardedHeadersTrustedIPs:
# Cloudflare IPs
- "173.245.48.0/20"
- "103.21.244.0/22"
- "103.22.200.0/22"
- "103.31.4.0/22"
- "141.101.64.0/18"
- "108.162.192.0/18"
- "190.93.240.0/20"
- "188.114.96.0/20"
- "197.234.240.0/22"
- "198.41.128.0/17"
- "162.158.0.0/15"
- "104.16.0.0/13"
- "104.24.0.0/14"
- "172.64.0.0/13"
- "131.0.72.0/22"
# Local IPs
- "10.0.10.23/32"
- "10.0.20.0/24"
# Local IPs
clientTrustedIPs:
- "192.168.0.0/16"
- "10.0.0.0/8"
- "172.16.0.0/12"


drop-ip-access.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
http:
routers:
catchall-http:
rule: "HostRegexp(`{host:.+}`)"
entryPoints:
- web
service: "blackhole-http-svc" # 指向HTTP黑洞服务
priority: 1

services:
blackhole-http-svc:
loadBalancer:
servers:
- url: "http://10.255.255.1:80"

# TCP部分:处理所有未匹配的HTTPS请求 (例如 https://<IP>)
tcp:
routers:
catchall-tls:
rule: "HostSNI(`*`)" # 匹配任何TLS连接
entryPoints:
- websecure
service: "blackhole-tcp-svc" # 指向TCP黑洞服务
priority: 1
tls:
passthrough: false

services:
blackhole-tcp-svc:
loadBalancer:
servers:
# TCP服务使用 'address' 字段
- address: "192.0.2.1:1"

crowdsec 配置

这里配置 CrowdSec,通过 docker 搭建。

整个安全方案由两部分组成:

  1. CrowdSec Agent (crowdsec 服务): 负责分析日志、检测威胁,并管理决策(例如,哪个 IP 应该被禁止)。
  2. Traefik Bouncer (作为 Traefik 插件): 在 Traefik 中运行,负责执行 CrowdSec Agent 的决策,直接在流量入口处阻止恶意 IP。

工作流程

  1. Traefik 接收外部请求,并将访问日志(JSON 格式)输出。
  2. CrowdSec Agent (crowdsec 服务) 通过挂载的 Docker Socket 读取 Traefik 的日志。
  3. Agent 使用 crowdsecurity/traefik collection 中的解析器和场景分析日志,检测到攻击行为(如暴力破解、扫描等)。
  4. 一旦检测到威胁,CrowdSec 会生成一个“决策”,将攻击者的 IP 标记为恶意,并推送到 local API。
  5. local API马上推送到所有Bouncer(如果还配置了其他Bouncer),其中Traefik 中的 CrowdSec Bouncer 插件会获取最新的决策列表。
  6. 当被标记为恶意的 IP 再次尝试访问时,Bouncer 会在 Traefik 层面直接拒绝该请求,从而保护所有后端服务。
crowdsec-bouncer-traefik-plugin.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
services:
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
restart: unless-stopped
environment:
- GID=999
- COLLECTIONS=crowdsecurity/traefik #安装了 crowdsecurity/traefik 集合,CrowdSec 知道 Traefik 日志长什么样。当它发现某个容器(也就是 Traefik 容器)的日志格式与 Traefik 解析器匹配时,就会自动开始采集和分析这些日志。
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro #允许 CrowdSec 监控其他容器的日志
- ./data:/var/lib/crowdsec/data
- ./config:/etc/crowdsec
networks:
- traefik-net

networks:
traefik-net:
external: true

反代配置

主要通过 traefik 的标签(labels)来配置反代。

docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
# ports:
# - "3000:3000"
environment:
DATABASE_URL:
DATABASE_TYPE: postgresql
init: true
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
interval: 5s
timeout: 5s
retries: 5
networks:
- traefik-net
labels:
- traefik.enable=true
- traefik.http.routers.umami.rule=Host(`stats.xingpingcn.top`) # 替换为你的域名。会自动帮你申请证书,记得把ip指向vps ip或者cname到cf的cdn
- traefik.http.services.umami.loadbalancer.server.port=3000 # umami 默认端口。traefik会主动处理,不需要要你自己设置端口。如果有另一个服务在网络traefik-net上监听3000端口,traefik会自动处理冲突。服务b想连接此服务,直接使用服务名和端口,例如 `http://umami:3000`
- traefik.http.routers.umami.entrypoints=websecure
- traefik.http.routers.umami.tls=true
- traefik.http.routers.umami.tls.certresolver=myresolver # 使用之前定义的证书解析器
- traefik.http.routers.umami.tls.options=cloudflare-mtls@file # 使用之前定义的 mtls 选项。traefik似乎不支持全局设置

networks:
traefik-net:
name: traefik-net
external: true

让在vpc中的aws lambda函数不通过nat获得访问互联网的能力

2025-06-22 22:37:56

如果在使用aws lambda中,你的lambda函数需要访问aws的其他服务,例如EFS、RDS,那么大概率需要将你的lambda和efs放置在同一vpc中(不在同一vpc的情况下你可以使用endpoint),这个时候即使你的lambda是在公开子网(public subnet)中也是是没有访问互联网的能力的,这是因为你的lambda只有子网的ip10.0.0.0,流量路由到互联网网关的时候会被网关丢弃,因为你没有配置公网ip。本文会给出几个解决方案,并分析优缺点。

因为aws的文档大部分是英文,中文文档都是机翻,所以有些专有名词的翻译就很别扭,所以干脆直接用英文。

前言

正如前面所说,你的lambda函数所在的vpc需要配置公网ip才能拥有访问互联网的能力。你可能会说,为什么我平时用的lambda不需要加入vpc呢?

这是因为:

  1. 你的lambda没有手动配置vpc。如果你的lambda没有手动配置vpc,那么aws会把你的lambda放进aws自己管理的vpc中,在该vpc中拥有公网ip,你的lambda可以访问互联网,但是你的lambda函数并不能访问该vpc下的其他aws服务(当然不能,难道你还能访问aws他自己的私有服务吗)
  2. 你的lambda并没有使用到其他aws服务。要使用其他aws服务,则该服务一定是要加入到你自己的vpc中的,例如你要把信息写进json文件并持久化,你需要s3或者EFS;例如你要访问ec2实例或RDS数据库。如果只是临时写入文件则可以在/tmp目录下写入,lambda运行结束则会被清空,不能持久化。

要让lambda拥有同时访问互联网和vpc下的服务的能力,首先你要有公网ip,另外你的lambda能访问vpc下的服务。

我查阅了网上提到的几种方法,并总结下来

存在的解决方案有:

  1. 配置nat网关
  2. 配置endpoint。将你的程序解耦,分为两个lambda函数,一个用于访问互联网,另一个访问aws服务,二者通过endpoint进行通讯。
  3. 通过API gateway。同样地,你的程序需要解耦,其中用于访问aws服务的lambda被主lambda函数通过API调用。
  4. 通过aws lambda api。使用aws sdk(python使用boto3),通过invoke方法同步或异步调用另一个lambda。

解决方案

配置nat网关

这是官方推荐的方法。

如何配置

新建一个vpc,选择带有公网子网和私有子网的模板,然后勾选nat网关就可以。在可视化界面中你可以看到私有子网通过路由表(route table)将流量路由到nat网关。你把你的lambda和aws服务放进私有子网内,你的lambda就拥有了同时访问互联网和vpc下的aws服务的能力。路由表会根据destination帮你处理好一切。

优缺点

最简单也最贵。单单是一个nat网关开着它就要30美元一个月,转发的流量还需要另外收费。不清楚公网ip是否另外收费

配置endpoint

aws设置endpoint的目的是为了让处于不同的vpc下的服务不通过互联网而通过aws的内部网络相互通讯,从而减少安全风险。

如何配置

利用这个特性,你可以在将需要访问互联网的lambda放在aws他自己管理的vpc中(在创建lambda的时候默认会放进该vpc),将另一个lambda放到你的vpc中,该lambda函数用于访问同vpc下的aws服务,例如RDS。前者lambda通过endpoint访问后者。

值得注意的是,endpoint是安装在服务消费者(service consumers)上的,在上面的例子中,假设我是希望能访问互联网的lambda访问处于自定义vpc中的lambda,读取RDS数据并发送邮件。在这里,服务消费者是访问互联网的lambda,服务提供者(service providers)是处于自定义vpc中的lambda,前面提到,endpoint应该被安装在服务消费者——也就是访问互联网的lambda中,但是,该lambda是放在aws自己管理的vpc中的,我们没有权限去创建一个endpoint,只能改变思路,就像下面的图所示,把处于自定义vpc中的lambda作为服务消费者,读取数据库,之后通过endpoint调用vpc外面的lambda。

NOTE

在你的lambda中,可以通过编程的方式使用aws sdk(python是boto3)链接endpoint。sdk通常是发送一个http请求来调用endpoint

优缺点

  • 优点

    • 费用比nat低
    • 由于解耦,程序逻辑更加清晰,并且能提高复用率。如果你使用RDS,需要使用RDS proxy来复用同一个数据库连接。
  • 缺点

    • 高延迟+双重冷(热)启动
    • 受到lambda的并发限制。免费账号只有10个并发,如果你要多次读写数据库则速度会很慢

通过API gateway

API gateway的最佳用途应该是用来写REST api,你可以通过API gateway调用lambda函数

如何配置

编写两个lambda,其中用于访问aws服务的lambda设置API gateway触发器(trigger),因而用于访问互联网的lambda可以通过发送http请求到该url而调用另一个lambda,进而访问aws服务。

优缺点

  • 优点

    • 有免费额度
    • 不用设置endpoint
    • 可以使用http来调用,调用起来更加方便
    • 由于解耦,程序逻辑更加清晰,并且能提高复用率。如果你使用RDS,需要使用RDS proxy来复用同一个数据库连接。
  • 缺点

    • 高延迟+双重冷(热)启动
    • 受到lambda的并发限制。免费账号只有10个并发,如果你要多次读写数据库则速度会很慢

通过aws lambda api

和其他aws服务一样,lambda也有自己的api。其中就包括调用lambda函数的invoke方法。

如何配置

如果你使用python,详见invoke

优缺点

  • 优点

    • api本身免费,运行的lambda有免费额度
    • 由于解耦,程序逻辑更加清晰,并且能提高复用率。如果你使用RDS,需要使用RDS proxy来复用同一个数据库连接。
  • 缺点

    • 只能通过aws sdk使用,否则你要自行编写认证程序
    • 高延迟+双重冷(热)启动
    • 受到lambda的并发限制。免费账号只有10个并发,如果你要多次读写数据库则速度会很慢

使用rclone和alist加密和备份你的数据到公有云

2025-06-22 22:37:56

因为我用的甲骨文 vps,可能会玄学删 vps,所以需要频繁备份。放在国内公有云又怕审查,放谷歌微软的公有云容量又太少,歪门邪道又可能被删数据。有了 alist 就可以方便加密和解密数据,把加密后的数据放国内公有云就不怕审查了。用 alist 还有一个好处就是,如果你的数据同步到了多个公有云,alist 是可以很方便集中显示和管理公有云的文件的。rclone 也是常规的同步工具,直接备份 docker 文件夹就是了,这边就稍微记录一下。

前言

想要达成前面说到的目的,你需要:

需要的东西

  1. alist,并注册多个国内公有云账号,会把 vps 的数据同步到多个公有云
  2. 安装好 rclone。直接用官网提供的 bash,就没必要用 docker 了,因为可能要经常敲命令行,如果用 docker 还得进入 docker 才可以敲。

配置 alist

alist 可以很方便加密数据并上传到公有云。见官网教程

这里稍微说明一下怎么做

  1. 先把公有云(如阿里云,天翼云)添加到alist
  2. 之后创建Crypt驱动,填写Crypt的路径,并且填写加密后的文件所在路径。例如,阿里云挂在到了/ali,那么需要在这个/ali里面预先创建一个空的文件夹,例如/ali/test,之后在Crypt配置里,填写Crypt本身的路径,例如/Crypt,之后填写加密后的文件所在路径,也就是/ali/test

那么就可以通过访问/Crypt来加密解密/ali/test里的文件了,上传文件到/Crypt也就同样可以加密文件到/ali/test

之后如果你选择把同一个文件加密到多个公有云,使用 alist 的别名功能可以方便集中显示和管理分布在各个公有云的文件。

同样不要忘记导出 alist 的配置,可以用中文的密码,更加难破解。在 alist 的 dash 中不能直接输入中文,可以在别处输入了密码后,再复制粘贴到 dash。

配置 rclone

通过 alist 来中转而不是直接在 rclone 中挂载公有云的原因是,rclone 挂载起来没有 alist 方便,而且 alist 文档写的比较清楚。我一开始是用 rclone 来挂载谷歌云盘的,官网教程用的谷歌云盘的 oauth api,结果弄到后面需要我在有浏览器的电脑里,下载 rclone 然后再用浏览器登录,把 cookie 复制到 vps,,,

rclone 可以直接挂载 alist 的 webdav,例如挂载 alist 的 /ali/test,就填写 http://127.0.0.1:port/dav/ali/test,注意你 alist 的端口,还要要加/dav前缀。

输入 rclone config 就可以挂载 webdav。webdav 的用户和密码同 alist 的登录用户密码。

配置同步

rclone sync and copy

rclone sync命令可以方便同步改变了内容的文件,例如 test.txt 中改变了一个字符,这时候运行同步命令就可以同步,如果再一次运行同步命令,则不会重复上传文件到公有云,节省了带宽。如果删除文件也会同步删除,rclone copy则不会同步删除。sync命令同样可以备份公有云端要删除的文件,具体见官网文档。

建议把同步命令写到 .sh 里,方便管理。rclone sync需要先了解怎么用。

/home/rclone/bash.sh
1
2
3
4
5
6
7
8
9
rclone sync /home/dcoker-data ali:/dcoker-data \
--copy-links --exclude-from /home/exclude.txt –ignore-size --disable-http-keep-alives --update

## --copy-links 复制软连接

## --exclude-from 排除某些文件或者文件夹。语法见 <https://rclone.org/filtering/>

# --dry-run 检查哪些文件要同步

可以在 exclude.txt 中定义不同步哪些文件。这里给一个样板。

/home/exclude.txt
1
2
3
4
5
6
7
tmp/**
icon_cache/**
**pycache**/**
netlify_cert/logs/**
\*.pem
alist/alist-data/log/**
alist/alist-data/temp/**

可以定时备份。

cron
1
2
3
4
5
6
7
8
9
10
11
12

# 手动把本文件放在/etc/cron.d

# 最后运行 service cron restart

# 如果需要使用其他用户运行,请改掉 root

# 需要注意的是最后的那个空行不能删除

SHELL=/bin/bash
0 0/8 \*\* ? root /bin/bash /home/rclone/bash.sh > /tmp/rclone.log 2>&1

cron笔记

2025-06-22 22:37:56

cron笔记,包含cron不执行shell脚本的解决办法

也许shell脚本本身可以执行,但是cron中不能执行,需要像下面这样设置

cron-for-run-per-1h.cron
1
2
3
SHELL=/bin/bash 
0 * * * * . /etc/profile;/bin/sh /pathto/run.sh

NOTE

最后一定要有一个回车!后者会导入失败

run.sh
1
2
3
4
5
#!/bin/bash
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LOGS_FILE="/pathto/logs/$(date "+%Y-%m-%d-%H-%M-%S").log"
cd /pathto
docker-compose up >> $LOGS_FILE 2>&1

最后设置到cron

run.sh
1
crontab /pathto/cron-for-run-per-1h.cron

warning

使用此命令会覆盖之前所有的cron任务

如果你不想覆盖之前的,那么就/etc/cron.d中新建文件,然后写进去。

warning

cron的话基本必有一个?,它仅可存在于dayofmouth或者dayofweek

个人docker配置备份

Dockerfile
1
2
3
4
5
6
FROM python:3.11
WORKDIR /bin/test
COPY ./requirements.txt ./
RUN pip install -r ./requirements.txt
ENTRYPOINT [ "python" ]
CMD [ "./test.py" ]
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3.8'
services:
enhanced-faas:
build:
context: ./
container_name: enhanced-faas
volumes:
- "./:/bin/test"
expose:
- 443,80
command: ./main.py
networks:
- nginx-proxy

networks:
nginx-proxy:
external: true

curl遇到的坑

2025-06-22 22:37:56

一开始我是这么写的

bash
1
2
3
4
5
6
7
8
9
10
11
12
# 获取更新后的证书和私钥文件路径
CERT_PATH=$(cat ./netlify_cert/domain.com.cert.pem)
KEY_PATH=$(cat ./netlify_cert/domain.com.key.pem)
FULLCHAIN_CERT_PATH=$(cat ./netlify_cert/domain.com.fullchain.pem)

# 使用 Netlify API 上传证书
curl -X POST \
-H "Authorization: Bearer $NETLIFY_API_KEY" \
-d "key=${KEY_PATH}" \
-d "ca_certificates=${FULLCHAIN_CERT_PATH}" \
-d "certificate=${CERT_PATH}" \
"https://api.netlify.com/api/v1/sites/${NETLIFY_SITE_ID}/ssl"

这么写看着没用什么问题,但是-d命令是默认进行urlencode的,这样子我的证书就会改变。需要改成--form-string才行。

这种默认就urlencode的,curl -h中又没说明,真的好坑

你的常用域名被其他vercel账号使用的解决方法

2025-06-22 22:37:56

先放链接

由于vercel最近在你的个人账户里添加了一个团队(team),你会发现你左上角的头像变了,然后点击中间domain按钮的时候发现里面并没有你之前使用过的域名。这个时候你在项目里添加域名,会提示说域名已经被其他账号使用。但是很困惑的是,只在前几天之前,你一直能够没有限制地添加域名,为什么这几天就变了。

这是由于你的项目现在全部变为你的team的项目,而你的域名却仍然在你的账号之下。

解决方法也很简单,点击右上角你的账号设置,然后点击左边的domain,选择你想要转移的域名,点击左边的三个点的按钮,然后点击move,就可以开始转移了。