写在前面
这里会分享什么呢?
依旧是实用性相对比较强的技术内容,用于解决一些具体的场景问题。
更新计划和频率
在文档目录树的左侧可以看到暂定的一些内容,稍后我会逐步添加。
当前的内容更新规划由内网中的 Phabricator 管理,暂时不好公开,晚些时候转换为 Roadmap。
发布方式暂时为 CI 从静态文档中构建,计划随后修改为由 Outline 中抽取合适内容即时生成。
自动申请 HTTPS 证书
本站当前使用的配置如下,修改配置中的变量即可直接使用,我使用的是 Cloudflare 作为 DNS 服务商,如果你使用其他服务商,可以查阅 Traefik 官方文档,替换变量名称即可。
docker-compose.yml
version: "3"
services:
traefik:
container_name: traefik
image: traefik:v2.4.11
restart: always
ports:
- 80:80
- 443:443
networks:
- traefik
environment:
- CF_API_EMAIL=你的邮箱
- CLOUDFLARE_DNS_API_TOKEN=你的API TOKEN
- CLOUDFLARE_ZONE_API_TOKEN=你的API TOKEN
command:
- "--global.sendanonymoususage=false"
- "--global.checknewversion=false"
- "--entrypoints.http.address=:80"
- "--entrypoints.https.address=:443"
- "--entryPoints.http.forwardedHeaders.trustedIPs=127.0.0.1/32,172.18.0.1/24"
- "--entryPoints.https.forwardedHeaders.trustedIPs=127.0.0.1/32,172.18.0.1/24"
- "--api=true"
- "--api.insecure=true"
- "--api.dashboard=true"
- "--api.debug=false"
- "--ping=true"
- "--log.level=trace"
- "--log.format=common"
- "--accesslog=false"
- "--providers.docker=true"
- "--providers.docker.watch=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.endpoint=unix:///var/run/docker.sock"
- "--providers.docker.swarmMode=false"
- "--providers.docker.useBindPortIP=false"
- "--providers.docker.network=traefik"
- "--providers.file=true"
- "--providers.file.watch=true"
- "--providers.file.directory=/etc/traefik/config"
- "--providers.file.debugloggeneratedtemplate=true"
- "--certificatesresolvers.le.acme.email=你的邮箱"
- "--certificatesresolvers.le.acme.storage=/data/ssl/acme.json"
- "--certificatesresolvers.le.acme.dnsChallenge.resolvers=1.1.1.1:53,8.8.8.8:53"
- "--certificatesresolvers.le.acme.dnsChallenge.provider=cloudflare"
- "--certificatesresolvers.le.acme.dnsChallenge.delayBeforeCheck=30"
volumes:
# 仅限标准的 Linux 环境使用
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/:/etc/traefik/config/:ro
- ./ssl/:/data/ssl/
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
# 处理网页
- "traefik.http.routers.traefik-dash-web.tls.certresolver=le"
- "traefik.http.routers.traefik-dash-web.tls.domains[0].main=suyang.wiki"
- "traefik.http.routers.traefik-dash-web.tls.domains[0].sans=*.suyang.wiki,*.console.suyang.wiki,*.demo.suyang.wiki"
- "traefik.http.routers.traefik-dash-web.tls=true"
- "traefik.http.routers.traefik-dash-web.middlewares=common-auth@file"
- "traefik.http.routers.traefik-dash-web.entrypoints=https"
- "traefik.http.routers.traefik-dash-web.rule=Host(`traefik.suyang.wiki`) && PathPrefix(`/`)"
- "traefik.http.routers.traefik-dash-web.service=dashboard@internal"
# 处理接口
- "traefik.http.routers.traefik-dash-api.middlewares=common-auth@file"
- "traefik.http.routers.traefik-dash-api.entrypoints=https"
- "traefik.http.routers.traefik-dash-api.rule=Host(`traefik.suyang.wiki`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
- "traefik.http.routers.traefik-dash-api.tls=true"
- "traefik.http.routers.traefik-dash-api.service=api@internal"
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"]
interval: 3s
retries: 12
logging:
driver: "json-file"
options:
max-size: "1m"
networks:
traefik:
external: true
config/default.toml
一些常用的中间件声明配置,可以不进行配置。
# 提供 Gzip 压缩
[http.middlewares.gzip.compress]
# 独立协议跳转规则
[http.middlewares.redir-https.redirectScheme]
scheme = "https"
# 兼容一些旧的配置,确认没有使用则可以删除
[http.middlewares.https-redirect.redirectScheme]
scheme = "https"
# 定义一个空服务,用于一些特殊场景
[http.services]
[http.services.noop.LoadBalancer]
[[http.services.noop.LoadBalancer.servers]]
url = "" # or url = "localhost"
# 定义一个简单的 BA 验证
[http.middlewares.common-auth.basicAuth]
users = [
# htpasswd -nb your-user-name your-pass-word
"your-user-name:$shdsdfiuysdiufywiuhreiwhf.",
]
removeheader = true
config/tls.toml
相对比较宽容的 A+ 评分的配置。
[tls]
[tls.options]
[tls.options.default]
minVersion = "VersionTLS12"
sniStrict = true
cipherSuites = [
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
]
Refs
使用 Traefik 和 Nginx 快速搭建静态网站
有的时候仅需要将一些静态文件和域名进行“绑定”展示,相比直接使用 Nginx,配合 Traefik 可以更加灵活。
version: "3"
services:
nginx:
image: nginx:1.21.1-alpine
restart: always
expose:
- 80
networks:
- traefik
volumes:
- ./public:/usr/share/nginx/html:ro
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.docs-homepage-0.middlewares=redir-https@file"
- "traefik.http.routers.docs-homepage-0.entrypoints=http"
- "traefik.http.routers.docs-homepage-0.rule=Host(`suyang.wiki`, `www.suyang.wiki`)"
- "traefik.http.routers.docs-homepage-1.middlewares=gzip@file"
- "traefik.http.routers.docs-homepage-1.tls=true"
- "traefik.http.routers.docs-homepage-1.entrypoints=https"
- "traefik.http.routers.docs-homepage-1.rule=Host(`suyang.wiki`, `www.suyang.wiki`)"
- "traefik.http.services.docs-homepage-backend.loadbalancer.server.scheme=http"
- "traefik.http.services.docs-homepage-backend.loadbalancer.server.port=80"
logging:
driver: "json-file"
options:
max-size: "1m"
networks:
traefik:
external: true
域名复用其实也很简单,只需要单独设置 Prefix
字段即可。
version: "3"
services:
nginx:
image: nginx:1.21.1-alpine
restart: always
expose:
- 80
networks:
- traefik
volumes:
- ./public:/usr/share/nginx/html:ro
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.runbook.middlewares=gzip@file"
- "traefik.http.routers.runbook.entrypoints=https"
- "traefik.http.routers.runbook.tls=true"
- "traefik.http.routers.runbook.rule=Host(`suyang.wiki`) && PathPrefix(`/runbook`)"
- "traefik.http.services.runbook-backend.loadbalancer.server.scheme=http"
- "traefik.http.services.runbook-backend.loadbalancer.server.port=80"
logging:
driver: "json-file"
options:
max-size: "1m"
networks:
traefik:
external: true
私有化部署
关于 Outline 的私有化,我已经写过两篇简单的文章来介绍如何使用,根据文章“一路Next”,就可以啦。
上面两篇文章默认读者已经配置了 Traefik ,所以并没有展开介绍如何配置使用 Traefik,如果你还不会使用 Traefik,可以参考下面的文章进行搭建使用。
为镜像打网卡驱动拾遗
因为 ESXi 6.x 与 7.x 的网卡 API 版本不一致,所以这两个版本的网卡驱动不能够混用。
然而,有一些网卡驱动目前暂时没有 7.x 版本的适配文件,所以我们如果想在一些老设备上使用 ESXi ,可能不得不使用 6.x 版本的软件。
我选择的基础镜像版本是:ESXi-6.7.0-20191204001-standard
镜像下载地址:
https://customerconnect.vmware.com/cn/downloads/details?downloadGroup=ESXI67U3B&productId=742
驱动下载可以从 v-front.de 下载,也可以到厂商的下载中心进行下载(比如 dell、lenovo 等),但是不建议使用社区远古版本的驱动(尤其是 issue 反馈了大量未解决 bug 的项目)
https://vibsdepot.v-front.de/wiki/index.php/Net55-r8168
在《NUC 折腾笔记 - 安装 ESXi 7》中,我基本对 7.x 版本的镜像打驱动补丁的方式做了完整介绍。
但是在 6.x 中,命令需要一些变动,多一步修改系统允许加载的外部驱动等级,将默认等级降低至“接受社区驱动软件”
New-EsxImageProfile -CloneProfile "ESXi-6.7.0-20191204001-standard" -name "ESXi-6.7.0-20191204001-nic" -vendor "soulteary"
Set-EsxImageProfile -Name "ESXi-6.7.0-20191204001-nic" -AcceptanceLevel CommunitySupported
Add-EsxSoftwarePackage -ImageProfile "ESXi-6.7.0-20191204001-nic" -SoftwarePackage "net55-r8168"
Export-EsxImageProfile -ImageProfile "ESXi-6.7.0-20191204001-nic" -ExportToISO -filepath .\exsi6.7.0.iso
笔记本使用细节
虽然使用笔记本安装 PVE 能够默认拥有双网卡、自带键盘和显示器的终端。但是默认情,操作键盘进行输入会不时得到刺耳的警告蜂鸣声音。
触发这个声音的原理是终端使用类似 Tab 进行补全的时候,触发类似下面的行为:
echo -e '\a'
解决问题需要编辑 /etc/inputrc
文件,将以下配置禁用掉:
# do not bell on tab-completion
# set bell-style none
# set bell-style visible
PHP
偷懒小技巧
有一些时候,我们需要使用临时的 PHP 仿真环境调试需要输出交互的代码,命令行直接执行代码,配合 curl 来搞太低效了,可以使用下面的方式,快速创建一个容器环境:
(默认环境缺少不少组件,所以你也可以换成你封装好的镜像来玩)
docker run -d -p 11080:80 -v "$(pwd)/index.php":/var/www/html/index.php php:7.4-apache
Docker
alpine 小技巧
偶尔使用 alpine 进行封装或者 shell 进行调试开发的时候,安装软件特别慢,可以考虑使用下面的方式快速切换软件源。
sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
MySQL小技巧
批量移除一定相同命名前缀的数据表
不知道哪个有才的脚本,在数据库里加了一堆无意义前缀的表。
删除方式很多,然而最终都是殊途同归,比如读出所有表名称,然后输出删表语句。
这里可以选择直接用 SQL 解决问题:
SELECT CONCAT('drop table ', table_name, ';')
FROM information_schema.tables
WHERE table_schema= 'YourDatabase'
AND table_name LIKE 'prefix_%' ;
手动转换表数据默认字符集
有一些云控制台实现的非常粗糙,创建的时候选项比较单一,选择不到我们所需要的字符集,只能靠创建后手动调整了:
ALTER DATABASE dbname CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE `tbname` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ALTER TABLE `tbname` DEFAULT CHARACTER SET=utf8mb4, COLLATE=utf8mb4_bin;
另外,为了避免转换过程中失败,可以调整 innodb_large_prefix on
参数
这里可以借助灵活的 js 来快速解决战斗,批量生成转换语句:
tpl = (tblName)=>`ALTER TABLE \`${tblName}\` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`;
tables = `history
...
...
...
user_relation
usercontent_relation
users`.split('\n').filter(n=>n).map(n=>tpl(n))
console.log(tables.join('\n'))
快速查阅 Ubuntu 变更日志
Ubuntu 有一个使用 Nginx AutoIndex 提供服务的站点,里面提供了各个版本的 changelogs 速查的方式。
- https://changelogs.ubuntu.com/