Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] 7ac6719aa9
Merge f990f26a2e into 5fedfd137a 2023-12-11 02:02:09 -08:00
31 changed files with 33 additions and 1860 deletions

4
.gitignore vendored
View File

@ -5,6 +5,4 @@ db.json
node_modules/ node_modules/
public/ public/
.deploy*/ .deploy*/
_multiconfig.yml _multiconfig.yml
.vscode
.idea/*

View File

@ -202,8 +202,8 @@ website_count:
analytics: analytics:
umami: umami:
umami_enable : true umami_enable : true
umami_src: "https://umami.lianglianglee.com/script.js" umami_src: "http://analyze.lianglianglee.com/umami.js"
umami_data_id: "c45fa8bb-5a87-4991-975c-b53e8224b33c" umami_data_id: "17ea0407-527d-4c0b-ae64-3bdf28f5678a"
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# Local Search # Local Search
# Docs: https://keep-docs.xpoet.cn/tutorial/configuration-guide/local_search.html # Docs: https://keep-docs.xpoet.cn/tutorial/configuration-guide/local_search.html
@ -220,7 +220,7 @@ local_search:
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
comment: comment:
enable: false # Option values: true | false enable: false # Option values: true | false
use: artalk # Option values: valine | gitalk | twikoo | waline | artalk use: valine # Option values: valine | gitalk | twikoo | waline
# Valine # Valine
# See: https://github.com/xCss/Valine # See: https://github.com/xCss/Valine
@ -257,9 +257,7 @@ comment:
server_url: # Server URL server_url: # Server URL
reaction: false # Article reactions, Option values: true | false reaction: false # Article reactions, Option values: true | false
version: 2 # Waline version, default use v2 version: 2 # Waline version, default use v2
artalk:
server:
site:
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# RSS # RSS
# Docs: https://keep-docs.xpoet.cn/tutorial/configuration-guide/rss.html # Docs: https://keep-docs.xpoet.cn/tutorial/configuration-guide/rss.html
@ -296,7 +294,7 @@ pjax:
# Docs: https://keep-docs.xpoet.cn/tutorial/configuration-guide/footer.html # Docs: https://keep-docs.xpoet.cn/tutorial/configuration-guide/footer.html
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
footer: footer:
since: 2024 # The starting year of your website, Can be null since: 2023 # The starting year of your website, Can be null
icp: # ICP record number of your website, Can be null icp: # ICP record number of your website, Can be null
site_deploy: site_deploy:
enable: false # Option values: true | false enable: false # Option values: true | false

View File

@ -14,24 +14,12 @@ timezone: 'Asia/Shanghai'
# URL # URL
## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project' ## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project'
url: https://blog.lianglianglee.com url: https://blog.lianglianglee.com
permalink: posts/:abbrlink.html permalink: :year/:month/:day/:title/
permalink_defaults: permalink_defaults:
pretty_urls: pretty_urls:
trailing_index: false # Set to false to remove trailing 'index.html' from permalinks trailing_index: true # Set to false to remove trailing 'index.html' from permalinks
trailing_html: false # Set to false to remove trailing '.html' from permalinks trailing_html: true # Set to false to remove trailing '.html' from permalinks
abbrlink:
alg: crc32 #支持crc16和crc32算法默认crc16
rep: hex #支持dec和hex值默认dec
drafts: false #(true)Process draft,(false)Do not process draft. false(default)
# Generate categories from directory-tree
# depth: the max_depth of directory-tree you want to generate, should > 0
auto_category:
enable: true #true(default)
depth: #3(default)
over_write: false
auto_title: false #enable auto title, it can auto fill the title by path
auto_date: false #enable auto date, it can auto fill the date by time today
force: false #enable force mode,in this mode, the plugin will ignore the cache, and calc the abbrlink for every post even it already had abbrlink.
# Directory # Directory
source_dir: source source_dir: source
public_dir: public public_dir: public
@ -121,15 +109,9 @@ search:
content: true content: true
format: striptags format: striptags
feed: feed:
type: type: atom
- atom path: atom.xml
- rss2
path:
- atom.xml
- rss2.xml
limit: 20 limit: 20
content_limit: 100
order_by:
plausible: plausible:
enable: true enable: true
domain: lianglianglee.com domain: lianglianglee.com

107
package-lock.json generated
View File

@ -9,7 +9,6 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"hexo": "^6.3.0", "hexo": "^6.3.0",
"hexo-abbrlink": "^2.2.1",
"hexo-bridge": "^1.2.0", "hexo-bridge": "^1.2.0",
"hexo-filter-plantuml": "^2.1.1", "hexo-filter-plantuml": "^2.1.1",
"hexo-generator-archive": "^2.0.0", "hexo-generator-archive": "^2.0.0",
@ -262,11 +261,10 @@
} }
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.3", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "license": "MIT",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": { "dependencies": {
"fill-range": "^7.1.1" "fill-range": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@ -617,9 +615,8 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/ejs": { "node_modules/ejs": {
"version": "3.1.10", "version": "3.1.9",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "license": "Apache-2.0",
"integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
"dependencies": { "dependencies": {
"jake": "^10.8.5" "jake": "^10.8.5"
}, },
@ -736,9 +733,8 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.1.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "license": "MIT",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
}, },
@ -763,15 +759,14 @@
} }
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.6", "version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh" "url": "https://github.com/sponsors/RubenVerborgh"
} }
], ],
"license": "MIT",
"engines": { "engines": {
"node": ">=4.0" "node": ">=4.0"
}, },
@ -817,19 +812,6 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC" "license": "ISC"
}, },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.1", "version": "1.1.1",
"license": "MIT" "license": "MIT"
@ -945,51 +927,6 @@
"url": "https://opencollective.com/hexo" "url": "https://opencollective.com/hexo"
} }
}, },
"node_modules/hexo-abbrlink": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/hexo-abbrlink/-/hexo-abbrlink-2.2.1.tgz",
"integrity": "sha512-yvazN7bbrIb7p8QU3nJ/8fbDmir1mFroYvUYcJz5xpc6DtszKggschmqZg6WNUdjhDBFyDwksrIUfwQnw0OOuA==",
"dependencies": {
"hexo-front-matter": "^1.0.0",
"hexo-fs": "^3.1.0"
}
},
"node_modules/hexo-abbrlink/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/hexo-abbrlink/node_modules/hexo-front-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexo-front-matter/-/hexo-front-matter-1.0.0.tgz",
"integrity": "sha512-Hn8IIzgWWnxYTekrjnA0rxwWMoQHifyrxKMqVibmFaRKf4AQ2V6Xo13Jiso6CDwYfS+OdA41QS5DG1Y+QXA5gw==",
"dependencies": {
"js-yaml": "^3.13.1"
},
"engines": {
"node": ">=8.6.0"
}
},
"node_modules/hexo-abbrlink/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/hexo-abbrlink/node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
"node_modules/hexo-bridge": { "node_modules/hexo-bridge": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/hexo-bridge/-/hexo-bridge-1.2.0.tgz", "resolved": "https://registry.npmjs.org/hexo-bridge/-/hexo-bridge-1.2.0.tgz",
@ -1527,8 +1464,7 @@
}, },
"node_modules/is-number": { "node_modules/is-number": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "license": "MIT",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"engines": { "engines": {
"node": ">=0.12.0" "node": ">=0.12.0"
} }
@ -1818,9 +1754,8 @@
} }
}, },
"node_modules/nunjucks": { "node_modules/nunjucks": {
"version": "3.2.4", "version": "3.2.3",
"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", "license": "BSD-2-Clause",
"integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==",
"dependencies": { "dependencies": {
"a-sync-waterfall": "^1.0.0", "a-sync-waterfall": "^1.0.0",
"asap": "^2.0.3", "asap": "^2.0.3",
@ -2390,8 +2325,7 @@
}, },
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "license": "MIT",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dependencies": { "dependencies": {
"is-number": "^7.0.0" "is-number": "^7.0.0"
}, },
@ -2407,9 +2341,8 @@
} }
}, },
"node_modules/tough-cookie": { "node_modules/tough-cookie": {
"version": "4.1.4", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", "license": "BSD-3-Clause",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"dependencies": { "dependencies": {
"psl": "^1.1.33", "psl": "^1.1.33",
"punycode": "^2.1.1", "punycode": "^2.1.1",
@ -2571,9 +2504,8 @@
} }
}, },
"node_modules/word-wrap": { "node_modules/word-wrap": {
"version": "1.2.5", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "license": "MIT",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -2583,9 +2515,8 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.18.0", "version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "license": "MIT",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },

View File

@ -13,7 +13,6 @@
}, },
"dependencies": { "dependencies": {
"hexo": "^6.3.0", "hexo": "^6.3.0",
"hexo-abbrlink": "^2.2.1",
"hexo-bridge": "^1.2.0", "hexo-bridge": "^1.2.0",
"hexo-filter-plantuml": "^2.1.1", "hexo-filter-plantuml": "^2.1.1",
"hexo-generator-archive": "^2.0.0", "hexo-generator-archive": "^2.0.0",

View File

@ -2,5 +2,4 @@
title: {{ title }} title: {{ title }}
date: {{ date }} date: {{ date }}
tags: tags:
permalink: /posts/
--- ---

View File

@ -1,180 +0,0 @@
---
title: 【发现好项目】给你的Postgres加个备份
tags: []
categories: []
abbrlink: fa974d33
date: 2024-07-29 23:03:04
---
GitHub地址<https://github.com/eduardolat/pgbackweb>
# 项目简介
使用用户友好的 Web 界面轻松备份 PostgreSQL
特点:
1. 界面友好简介
2. 备份上传到类S3存储
3. 支持定时备份
4. Web页面可直接下载备份
5. 敏感配置加密保存
缺点:
1. 不支持一键备份整个Server多个数据库需要多次配置
2. 连接字符串没有拆分,导致配置时需要注意格式
# 部署
```yaml
services:
pgbackweb:
image: eduardolat/pgbackweb:latest
ports:
- "8085:8085" # Access the web interface at http://localhost:8085
environment:
PBW_ENCRYPTION_KEY: "my_secret_key"
PBW_POSTGRES_CONN_STRING: "postgresql://postgres:password@postgres:5432/pgbackweb?sslmode=disable"
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16
environment:
POSTGRES_USER: postgres
POSTGRES_DB: pgbackweb
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- ./data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
```
替换掉环境变量PBW_ENCRYPTION_KEY 为任意字符串
如果变更POSTGRES_PASSWORD记得 PBW_POSTGRES_CONN_STRING 中的password也要变更
## 使用Minio作为备份后的存储
```yaml
version: "3.7"
services:
minio:
image: quay.io/minio/minio:RELEASE.2024-01-01T16-36-33Z
ports:
- 9000:9000
- 9001:9001
volumes:
- ./minio/minio:/data
command: server --console-address ":9001" /data
environment:
- MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE // 请自行变更
- MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY //请自行变更
```
浏览器打开 ip:9001
输入MINIO_ROOT_USERMINIO_ROOT_PASSWORD配置的账号密码
![Minio管理页](https://static.lianglianglee.com/2024/07/IM7MxgK.png)
Create a Bucket
![create a bucket](https://static.lianglianglee.com/2024/07/KCYMxgK.png)
创建完成后minio即配置完成
# 使用
整个功能分为三大块
* Database 配置需要备份的数据库链接信息
* Destinations 配置S3存储备份后的数据上传到该存储中
* Backups 备份的配置,什么时候备份,备份保存天数等
## 创建Database
![](https://static.lianglianglee.com/2024/07/WmcixgK.png)
Name可以自选我习惯用用IP+数据库名称
Version支持Pg13-Pg16
Connection string数据库的链接信息格式为
```yaml
postgresql://userName:password@hostname:5432/databaseName?sslmode=disable
```
比如
```yaml
postgresql://postgres:password@postgres:5432/pgbackweb?sslmode=disable
```
测试后保存
## 创建Destination
这里使用类S3存储都可以比如七牛云阿里云的OSS自建的Minio都可以。这里以Minio为例
![create destination](https://static.lianglianglee.com/2024/07/ASnmxgK.png)
Name可以自定义我习惯用服务所在地+服务类型
Bucket Name 需要填写Minio中的Bucket
Endpoint 服务器的IP及端口请注意这里要pgbackweb容器能访问的地址端口使用90009001是管理的Web网页
Region 可随意填写
Access KeySecret key 填写Minio的默认用户名密码即可。当然你也可以在MinioConsole再生成一个这里不建议生成。
点击Test Connection 右下角跳出`Connection successful`代表配置没问题
## 配置Backup
![create backup](https://static.lianglianglee.com/2024/07/5XDnxgK.png)着重介绍几个选项
Database 选择已经创建的数据库连接
Destination 选择已创建的存储地址多个Database可以用一个用的Destnation directory区分即可
Cron是不带星期的格式比如每天夜里2点 备份:`0 2 * * *`
Time zone是Cron表达式的时区选自己所在的时区即可
Destnation directory是在S3中的文件夹这里可以使用Database名称作为文件夹更方便区分
Retention days 保留天数,自定义,当然也要看备份存储的成本
Options 无特殊要求默认即可
保存后,点击小闪电,即可立即执行备份
![backup list](https://static.lianglianglee.com/2024/07/BUROxgK.png)
## 查看备份情况
在Executions可以看到备份的执行状态。
![executions list](https://static.lianglianglee.com/2024/07/2bzOxgK.png)
进入Minio可以看到文件夹名称就是在Backup中填写的文件夹
![minio list](https://static.lianglianglee.com/2024/07/Qz3oxgK.png)可以一层一层点进去看备份的文件这里是tar压缩格式可以下载后解压查看SQL文件
# 总结
pgbackweb是一个很简介且入手难度极低的PostgreSQL备份工具新手完全可以直接上手。基本满足了我的数据库备份需求。

View File

@ -1,276 +0,0 @@
---
title: 使用R2+Page部署免费的图床【白嫖Cloudflare】
tags: []
categories: []
abbrlink: 22b7ecba
date: 2024-01-15 19:17:49
---
# 背景
作为一个程序员一般写文章都是使用markdown编写可以快速复制到其他平台上。然而markdown有一个严重的问题就是图片保存的问题。
刚开始我使用的typora作为编辑器图片保存在md文件同目录的assets文件夹。一直以来都是自己阅读后来有了在线阅读的需求就自己编写了一个markdown阅读工具完全根据自己的习惯编写。
后来做了博客面临复制到博客的需求每次编辑完再复制图片到博客的文件夹整个流程就繁琐了。故想一统markdown的图片存储。
现在的策略是使用picgo上传到R2上然而这个工具有一个严重的问题多客户端同步的问题。使用一段时间就不再使用了。
一直在想能不能做一个网页版的图床使用网页上传最好不做元数据存储直接读取R2的目录。
# 调研
程序员,就要自己**找**轮子github上搜搜一番找到一个还不错的工具https://github.com/roimdev/roim-picx
已经实现了这些功能,对我来说足够了
> * 图片批量上传
> * 图片列表查询
> * 图片删除
> * 目录创建
> * 按目录查询
> * 链接地址点击复制
> * 简单的身份认证功能,进入管理页面需要授权
部署上去试了试,整体对我来说很适合。其文档写的也不是很完善,就简单记录一下。
# 部署
该项目使用了Cloudflare的三个能力
1. **KV**Token存储
2. **R2**:图片存储
3. **Page**:提供页面访问
Page中使用了functions作为后端服务
## 准备工作
**创建KV存储**
登录Cloudflare账号`首页/Workers和Pages/KV`
创建一个命名空间
**创建R2存储**
进入`首页/R2`
创建存储桶。位置可自动
## fork仓库
## 部署
可按照教程部署
## 配置
因为其使用了KV和R2存储则需要在`page详情/设置/函数`中配置这两个变量\nKV命名绑定变量名称`XK`KV空间选刚才创建的
R2 存储桶绑定,变量名称`PICX`R2存储通选刚刚创建的
还需要配置一个环境变量`page详情/设置/环境变量`
新增`BASE_URL`,值空着不填即可
**Token配置**
其token是从KV存储中读取的所以需要进入KV存储
添加条目\n密钥`PICX_AUTH_TOKEN`,值可以自定义
**访问:**
![image.png](https://static.lianglianglee.com/2024/01/CkUQ8aK.png)
打开后,输入`PICX_AUTH_TOKEN`定义的值即可
# 魔改
作为一个开源项目肯定不会100%适合我,根据我的需求,做了一点点的改动。
1. 调整文件上传的存放路径为`年/月/文件`
2. 页面复制的URL为额外的域名+文件地址
3. KV只用来方Token太浪费Token更改为环境变量存储
4. 修改网站的标题Logo等
## 调整文件上传路径
原来的文件上传后,会传到根路径中,作为临时图床可以,如果作为静态图片存储,就不合适了,图片多了没办法处理
文件名称生成在`functions\rest\utils.ts`
修改`getFileName`为`getFilePath`,并做以下改动:
```javascript
// 获取文件名
export async function getFilePath(val: string, time: number): Promise<string> {
const types = supportFiles.filter(it => it.type === val)
if (!types || types.length < 1) {
return val
}
const rand = Math.floor(Math.random() * 100000)
const fileName = randomString(time + rand).concat(`.${types[0].ext}`)
let date = new Date()
const year = date.getFullYear() //获取完整的年份(4位)
let month = date.getMonth() + 1 //获取当前月份(0-11,0代表1月)
if (month < 10) {
month = `0${month}`;
}
return `${year}/${month}/${fileName}`
}
```
修改调用方:
全局搜索`getFileName`,替换成`getFilePath`
部署后,测试上传是否有问题
## 增加复制地址
想法如下:
原有的图片地址不变的情况下图片属性增加一个copyUrl的属性在列表上传后返回该属性域名配置使用环境变量
**环境变更**
`functions\rest\[[path]].ts`
```javascript
export interface Env {
BASE_URL: string
COPY_URL: string //新增
XK: KVNamespace
PICX: R2Bucket
}
```
在cloudflard的设置增加变量
**图片对象**
```javascript
export interface ImgItem {
key : string
url : string
size: number
copyUrl: string
filename ?: string
}
```
**API返回**
`functions\rest\routes\index.ts`
```javascript
// list接口
return <ImgItem>{
url: `/rest/${it.key}`,
copyUrl: `${env.COPY_URL}/${it.key}`,
key: it.key,
size: it.size
}
// 上传接口
urls.push({
key: object.key,
size: object.size,
copyUrl: `${env.COPY_URL}/${object.key}`,
url: `/rest/${object.key}`,
filename: item.name
})
```
**列表页面**
1. 传递参数
`src\views\ManageImages.vue`
```javascript
// image-box 增加copyUrl传递
<image-box
:src="item.url"
:copyUrl="item.copyUrl"
:name="item.key"
:size="item.size"
@delete="deleteImage(item.key)"
mode="uploaded"
/>
```
2. 接受入参
`src\components\ImageBox.vue`
```javascript
// 接受入参
const props = defineProps<{
src: string
copyUrl:string // 新增
name: string
size: number
mode: 'converted' | 'uploaded'
uploadedAt?: number
expiresAt?: number
}>()
---
//copyLink 方法入参修改为copyUrl
@click="copyLink(copyUrl)"
```
**上传页面**
`src\components\ImageItem.vue`
将`htmlLink`,`markdownLink`,`LINK`这三个地方的url改成`copyUrl`
## Token使用环境变量存储
环境变量在`functions\rest\[[path]].ts`
```javascript
export interface Env {
AUTH_TOKEN: string
COPY_URL: string
R2: R2Bucket
}
```
调用方修改`functions\rest\routes\index.ts`
```javascript
await env.XK.get('PICX_AUTH_TOKEN')
// 修改为:
env.AUTH_TOKEN;
```
新增环境变量:`AUTH_TOKEN`
环境变量修改完成后,记得重新部署
## 修改网站标题
网站首页在`src\App.vue`
直接修改部署即可。
# 其他
魔改后的代码地址:<https://github.com/liangliangle/roim-picx>

View File

@ -1,8 +1,6 @@
---
title: Debian创建Raid5阵列 title: Debian创建Raid5阵列
tags: [] tags: []
categories: [] categories: []
abbrlink: 77c1eb7c
date: 2023-06-29 01:12:23 date: 2023-06-29 01:12:23
--- ---

View File

@ -1,8 +1,6 @@
---
title: 使用Docker部署Java程序 title: 使用Docker部署Java程序
tags: [] tags: []
categories: [] categories: []
abbrlink: a1073832
date: 2023-05-17 21:59:19 date: 2023-05-17 21:59:19
--- ---
# 背景 # 背景

View File

@ -1,8 +1,6 @@
---
title: Docker部署Seafile服务 title: Docker部署Seafile服务
tags: [] tags: []
categories: [] categories: []
abbrlink: 1f9eb31a
date: 2023-07-04 19:58:00 date: 2023-07-04 19:58:00
--- ---
# 背景 # 背景

View File

@ -1,95 +0,0 @@
---
title: 记一次Dubbo invoke命令的问题
tags: []
categories: []
abbrlink: 851d3eeb
date: 2024-03-14 11:04:12
---
# 记一次Dubbo invoke命令的问题
# 背景
因为线上发生了一次死锁问题导致数据没有正常写入需要手动调用dubbo invoke重试。
接口入参为 String, String, Object
命令为:
```java
invoke xxService.xxMethod("123","321",{...})
```
愉快进入容器,开始执行,不出意外,意外就发生了
```java
Invalid json argument, cause: unclosed string :
```
# 排查
最开始以为是JSON格式有问题开始排查格式用了各种校验工具都没有发现问题
举例格式如下:
```json
{
"class": "xxx",
"xx": "xxx",
"xxx": "xxx",
"xxxx": "xxx",
"xxx": "xxxx",
"xxxRequest": {
"xxxNo": "xxx",
"xxxName": "xx(XXX)x"
},
"xxxItemDataList": [
{
"xxx": "xxx",
"xxx": "xxx",
"class": "xxx.xxx.xxx.xxx"
}
]
}
```
因为接口的入参是一个父类所以用class执行具体子类类型
list中同样也制定了类型
用了各种工具校验JSON都没有问题最后跟代码发现**是因为Json中的value有英文的括号导致命令解析出现了问题到括号就结束了解析**实际到Dubbo中的JSON是
```json
{
"class": "xxx",
"xx": "xxx",
"xxx": "xxx",
"xxxx": "xxx",
"xxx": "xxxx",
"xxxRequest": {
"xxxNo": "xxx",
"xxxName": "xx(XXX
```
这可不就是JSON格式有误吗
# 代码解析
dubbo分支切换到2.7.x
全局搜`Invalid json argument`,找到代码
![clipboard.png](https://static.lianglianglee.com/2024/03/Y018tCK.png)
按照第一个英文括号解析的,导致整个命令被强制截断。
再看一下最新代码 3.2的版本
![clipboard.png](https://static.lianglianglee.com/2024/03/3k3JtCK.png)
最新版已经修复了这个问题。
# 总结
当dubbo版本是2.7.x使用invoke时参数中不能有英文右括号

View File

@ -1,8 +1,6 @@
---
title: 记一次业务系统与ES的同步方案升级 title: 记一次业务系统与ES的同步方案升级
tags: [] tags: []
categories: [] categories: []
abbrlink: cbda41f1
date: 2023-08-28 15:05:47 date: 2023-08-28 15:05:47
--- ---
# 背景 # 背景

View File

@ -1,8 +1,6 @@
---
title: 从文件看Git title: 从文件看Git
tags: [] tags: []
categories: [] categories: []
abbrlink: e25aabb4
date: 2023-10-26 11:15:09 date: 2023-10-26 11:15:09
--- ---
# 从文件看Git # 从文件看Git

View File

@ -1,179 +0,0 @@
---
title: 全球访问加速调研
tags: []
categories: []
abbrlink: d1ec7f99
date: 2024-06-12 22:51:13
---
# **背景**
公司的所有业务系统都部署在上海地区,北美地区访问延迟不稳定。
以下为某服务的API接口主要业务地区的初次访问
接口:`https://xxxx.com/health/check`
| **地区** | **建连时间** | **首包时间** | **总耗时** |
| ---------- | ------------ | ------------ | ---------- |
| 加利福尼亚 | 160ms | 165ms | 1063ms |
| 弗吉尼亚 | 207ms | 220ms | 842ms |
| 新加坡 | 68ms | 74ms | 332ms |
| 上海 | 6ms | 19ms | 37ms |
| 深圳 | 34ms | 44ms | 303ms |
> 数据来源:<https://boce.aliyun.com/detect/http>
除了以上耗时,还有
1. DNS解析耗时
2. SSL握手耗时
3. 下载耗时
可以看到 北美访问基本耗时在1秒以上如果稳定的1秒钟的延迟问题也不算特别大然而延迟是不稳定的比如
![加利福尼亚-夜间延迟数据](https://static.lianglianglee.com/2024/06/Z1WIKFK.png)
![弗吉尼亚-夜间延迟数据](https://static.lianglianglee.com/2024/06/cJyIKFK.png)
数据来源:阿里云监控-定时拨测 晚上9点-第二天9点的响应时间
在高峰期可以看到在晚上9点后延迟就开始不稳定了美西延迟波动还不算大美东直接变为不可用了。
# 为什么会慢
说到那么慢,就需要先了解跨国流量是怎么走的[海缆地图](https://www.submarinecablemap.com/)
## 登录站
目前中国的登录站主要有以下几个地方
- [青岛](https://www.submarinecablemap.com/landing-point/qingdao-china)
- 上海
- [崇明](https://www.submarinecablemap.com/landing-point/chongming-china)
- [临港](https://www.submarinecablemap.com/landing-point/lingang-china)
- [南汇](https://www.submarinecablemap.com/landing-point/nanhui-china)
- [福州](https://www.submarinecablemap.com/landing-point/fuzhou-china)
- [汕头](https://www.submarinecablemap.com/landing-point/shantou-china)
- [北海](https://www.submarinecablemap.com/landing-point/beihai-china)
- [海南](https://www.submarinecablemap.com/landing-point/hainan-china)
- [文昌](https://www.submarinecablemap.com/landing-point/wenchang-china)
- [陵水](https://www.submarinecablemap.com/landing-point/lingshui-china)
## 走向分布
中美直连的线路目前只有两条
- [TPE](https://www.submarinecablemap.com/submarine-cable/trans-pacific-express-tpe-cable-system)(跨太平洋快线)
- [NCP](https://www.submarinecablemap.com/submarine-cable/new-cross-pacific-ncp-cable-system)(新跨太平洋海缆)
往东亚方向的的
- [APCN-2](https://www.submarinecablemap.com/submarine-cable/apcn-2)亚太2号海底光缆
- [APG](https://www.submarinecablemap.com/submarine-cable/asia-pacific-gateway-apg)(亚太直达国际海底光缆)
- [EAC-C2C](https://www.submarinecablemap.com/submarine-cable/eac-c2c)(东亚海底光缆)
- [SJC](https://www.submarinecablemap.com/submarine-cable/southeast-asia-japan-cable-sjc)(东南亚日本海底光缆)
- [ADC](https://www.submarinecablemap.com/submarine-cable/asia-direct-cable-adc)亚洲直线2024年Q4投入使用
- [SJC-2](https://www.submarinecablemap.com/submarine-cable/southeast-asia-japan-cable-2-sjc2)(东南亚-日本2号海底光缆2025年Q1投入使用
往欧洲方向
- [SEA-ME-WE-3](https://www.submarinecablemap.com/submarine-cable/seamewe-3)亚欧3号海底光缆
- [SEA-ME-WE-4](https://www.submarinecablemap.com/submarine-cable/seamewe-4)亚欧4号海底光缆
- [FEA](https://www.submarinecablemap.com/submarine-cable/flag-europe-asia-fea)(环球海底光缆)
往台湾方向
- [TSE-1](https://www.submarinecablemap.com/submarine-cable/taiwan-strait-express-1-tse-1)海峡光缆1号
## **为什么中国的跨国海底光缆那么少?**
因为跨国海底光缆不是一个国家的能建成的,有登陆站的国家都要参与建设,所以要**一拍即合**
拿跨太平洋快线举例参与的企业有【AT&T中国电信中华电信KTNTT Verizon】登陆站有6个【上海-崇明,山东-青岛,日本-东京,韩国-巨济,台湾-炭水,美国-俄勒冈】
![clipboard.png](https://static.lianglianglee.com/2024/06/iiIoKFK.png)
所以协同建造难。
晚间访问高峰时,公共线路丢包,拥堵情况严重,延迟爆炸
当然建造成本那么高,肯定要想办法盈利,故各运营方提供了付费的国际精品专线
# 加速访问
**以美国访问中国为例**
在美中之间,有两个使用高品质线路互联的服务器,两个服务器之间不存在阻塞,丢包情况。那就可以借助这两个服务器做一些改造。
美国用户访问美国的这个服务器由这个服务器把流量打到中国的这个服务器上再由中国的服务器向源服务器发起请求再把响应返回出去。那就形成3段稳定的链路
![clipboard.png](https://static.lianglianglee.com/2024/06/QcNUKFK.png)
高品跨国链路,一般企业不会采购,所以购买现成的是最佳选择,阿里云就提供这样的服务
## 不能解决什么?
全球加速不能解决传输时延问题。
比如中国到美西的访问传输时延在150毫秒左右。
## **阿里云全球加速**
![阿里云全球加速](https://static.lianglianglee.com/2024/06/XvfiKFK.png)
以中美间访问为例,无论是中国访问美国,还是美国访问中国,流量都是走**公共链路**。高峰期网络拥堵,丢包率、延迟都不可控且不稳定。
全球加速是中美间的流量**不走公共链路**,而是走阿里云的全球网络。基本不会产生拥堵,丢包情况,延迟可控且稳定。
## 加速方式
全球加速有三种接入方式,每种方式有不同的实现方式
1. 弹性公网IP
2. 任播弹性公网IP
3. CNAME
### 弹性公网IP
弹性公网IP简单来说就是每个地区提供单独的公网IP对应地区连接各自地区的IP
### 任播弹性公网IP
弹性公网IP有一个问题每个地区都有对应的IP没办法一个IP访问全部如果连接到错误地区的IP延迟更高。
这个时候借助任播技术就可以实现一个IP指定地区的访问。
> **[任播](https://zh.wikipedia.org/wiki/%E4%BB%BB%E6%92%AD)**(英语:**anycast**)是一种网络寻址和路由的策略,使得资料可以根据路由拓扑来决定送到"最近"或"最好"的目的地。
### CNAME
CNAME实际上是套了一层的DNS解析在阿里云的全球加速中最后解析到的IP依旧是一个任播公网IP
# **切换流程**
DNS切换会影响全部用户切换流程如下
## **验证期**
- 切换CNAME解析到全球加速的域名
- TTL设置为1分钟能选择的最短时间即可
## **验证**
1. 清空本地DNS缓存
2. 使用dig命令解析域名
1. dig xxxx.com
3. 本地访问`https://xxxx.com/health/check`
4. 使用加速地区的ECS或VPS等访问 `https://xxxx.com/health/check`
## **验证完成**
- 修改TTL恢复原本时长
------
## **回滚**
CNAME解析切换回原来的即可
> 切换时间视TTL不同有所不同一般会略高于TTL时间

View File

@ -1,8 +1,6 @@
--- title: 使用Hexo+cloudflare搭建个人博客[当前博客搭建过程]
title: '使用Hexo+cloudflare搭建个人博客[当前博客搭建过程]'
tags: [] tags: []
categories: [] categories: []
abbrlink: d3175a9a
date: 2023-04-05 14:38:18 date: 2023-04-05 14:38:18
--- ---
# 1 背景介绍 # 1 背景介绍

View File

@ -1,410 +0,0 @@
---
title: 制作CA签发验证SSL证书
tags: []
categories: []
date: '2024-01-12T17:05:48.000Z'
abbrlink: 54c1e4fe
---
# 背景
**为什么要用SSL**
对于我来说,最重要的就是**数据加密**。在互联网访问中HTTPS相比HTTP提供了TLS加密数据。别人只能看到你访问了某个域名和IP但是不知道我们之间传输了什么内容。
**TLS解决了什么**
1. 如何保证数据传输的保密性;
2. 如何保证数据传输的完整性;
3. 如何保证通信主体的真实性;
其一,它用对称加密方法加密中间来回传输的流量,使得中间节点只能看到密文,并且中间节点一般拿不到解密密钥把密文恢复成明文。
其二,它提供了端到端的安全性,就好像是在两个进程之间建立了一条坚实可靠的「管道」保护着管道里边传输的报文,使得数据在进程到进程之间的传播是完整的,就算被篡改了也是能检验得出的;
其三,它通过公钥加密的技术,结合现有的 PKI公钥密码学基础设施提供了通信双方验证对端身份真实性的一种机制
**为什么不用免费的SSL证书**
实际上我用了Cloudflare的服务后自动提供了SSL的证书且不需要关心有效期的问题。
但是 [在公司无感访问家里的服务](https://blog.lianglianglee.com/2024/01/11/office_visit_home_server/) 中办公环境下全程都是HTTP数据完全透明同样需要HTTPS为数据安全提供保障。
如果使用免费的证书则每三个月需要申请一次比较麻烦因为都是内网访问所以更简单一点直接用自己的根证书后续也能用于内网的各种HTTPS访问
**计算机怎么知道这个证书是可信的呢?**
操作系统通常会预装一组根证书Root Certificates作为信任锚点用于验证数字证书的真实性。这些根证书是由大型、受信任的CA签发的因此用户可以信任这些根证书从而信任由这些根证书签发的其他数字证书。这种信任链建立了对整个公共PKI的信任确保了数字证书的可信度。新的根证书可能会在操作系统更新中加入以适应不断变化的证书颁发机构和安全需求。
**获取TSL的流程**
获取TLSTransport Layer Security证书通常涉及以下步骤。因为TLS的前身是SSLSecure Sockets Layer所以经常会说SSL证书
1. 选择证书颁发机构
2. 生成证书签发请求CSR
3. 提交CSR到CA
4. 身份验证
5. 接受证书
6. 安装证书
主要流程如上实际过程中提交CSR身份验证接受证书都会受CA机构的影响会有所不同。
# 创建根证书
根据前面的介绍,我们只需要安装自己生成的根证书,那这个证书颁发的所有证书都是可信的。所以我们需要先生成一个根证书,然后让私有设备信任这个根证书。
> 对于这篇文章中讲到的根证书、普通证书,学名都是 X.509v3 证书,区别只在于:
>
>
> 1. 根证书是自己给自己签发的
> 2. 根证书和普通证书的扩展参数有些不一样
>
> \
> CA 证书也好普通证书也好,都可以统一地用 openssl 的那一套命令行工具来生成、签发、验证和查看,非常的方便。
接下来不涉及到 CRL 和 OCSP感兴趣的朋友可以自行查阅 Wikipedia 和 [rfc5280](https://datatracker.ietf.org/doc/html/rfc5280).
## 生成私钥
最好在一个单独的目录操作先生成一个CA私钥
```bash
openssl genrsa -out ca.key 2048
```
我们会得到一个 [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) 格式的私钥,它的默认 permissions 也很有意思:
```bash
ls -all ca.key
---
-rw------- 1 root root 1704 Dec 10 15:18 ca.key
```
接下来要开始签发自签证书,按照 openssl 的惯例,我们可以先把证书的一些信息写到一个配置文件中:包括这个证书对应的主体 (subject) 是谁、这个证书是做什么用的、这个证书的唯一标识和签发者的唯一标识等获取方式等:
```ini
[ req ]
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = v3_ca
[ req_distinguished_name ]
countryName = CN
stateOrProvinceName = Beijing
localityName = Beijing
0.organizationName = LocalOrganizationName
organizationalUnitName = IT
commonName = Homelab Root CA
emailAddress = admin@example.com
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:2
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
```
把它保存为当前目录的 `ca.root.ini` 文件。
> 希望进一步了解配置文件的格式以及其中各个字段含义的读者可以参阅 man 5 config 和 man 5 x509v3_config.
## 生成证书
```bash
openssl req -new -x509 -key ca.key -config ca.root.ini -out ca.crt
```
得到一个 PEM 格式的 `ca.crt` 文件位于当前文件夹。
我们可以通过 `openssl x509` 命令查看此证书的详细信息:
```bash
openssl x509 -in ca.crt -noout -text
---
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
60:9a:7a:ba:8c:98:9b:f8:1a:de:46:c4:0c:05:0c:7f:b2:b8:c9:ab
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com
Validity
Not Before: Jan 12 09:31:08 2024 GMT
Not After : Feb 11 09:31:08 2024 GMT
Subject: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bf:c3:ee:37:75:2d:15:9c:1a:dd:d7:77:5c:78:
.....略
dd:a7:5e:09:36:d4:87:96:0b:42:12:a3:fd:99:95:
8c:63
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
51:27:75:BE:3E:24:AE:A5:93:C7:1C:DE:F8:23:FB:7F:4D:BF:53:34
X509v3 Authority Key Identifier:
51:27:75:BE:3E:24:AE:A5:93:C7:1C:DE:F8:23:FB:7F:4D:BF:53:34
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:2
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
8a:c9:ab:63:2d:a2:aa:72:7b:d9:41:27:d2:5d:00:14:f0:77:
...略
76:08:94:3c:b5:24:12:0a:71:8a:46:60:5e:83:78:1d:09:68:
f3:80:87:0e
```
我们发现 X509v3 Subject Key Identifier 和 X509v3 Authority Key Identifier 有相同的值,前者是它自己的唯一编号,后者是签发此证书的证书的唯一编号,再结合 X509v3 Basic Constraints 的 CA:TRUE 字样,使得验证者可以判断它是一个自签的根 CA 证书。
这个 CA 证书的 pathlen 是 2这意味着它还可以再签发一个 pathlen 等于 1 的中级 CA 证书,然后这个 pathlen 等于 1 的中级 CA 证书自己又可以再签发一个 pathlen 等于 0 的中级 CA 证书pathlen 等于 0 的 CA 证书不能再签发 CA 证书,只能签发最终用户证书 (end-entity certificate).
我们可以用这行命令验证它:
```bash
openssl verify --show_chain -CAfile ca.crt ca.crt
---
ca.crt: OK
Chain:
depth=0: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com
```
接下来我们选择直接用它签发 end-entity certificate
# 证书签发
## 生成私钥
```bash
openssl genrsa -out x.com.key 2048
```
准备一个 `x.com.ini` 配置文件,填写主体信息:
```ini
[ req ]
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
countryName = CN
stateOrProvinceName = Beijing
localityName = Beijing
0.organizationName = LocalOrganizationName
organizationalUnitName = IT
commonName = Homelab Root CA
emailAddress = admin@example.com
subjectAltName=@SubjectAlternativeName
[ SubjectAlternativeName ]
DNS.1 = *.x.com
```
> 请注意SubjectAlternativeName模块这个地方是证书用于什么域名多个可以用
>
> ```ini
> DNS.1 = *.x.com
> DNS.2 = *.x.com
> ```
>
> 也可以指定IP
>
> ```ini
> DNS.1 = *.x.com
> DNS.2 = *.x.com
> IP.1 = xxx.xxx.xxx.xxx
> IP.2 = xxx.xxx.xxx.xxx
> ```
## 创建CSR (certificate signing request):
```bash
openssl req -new -key x.com.key -config x.com.ini -out x.com.csr
```
可以用下列命令来查看 CSR 信息,确保它已经有了对应的私钥和主体信息:
```ini
openssl req -in x.com.csr -noout -text
---
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com, subjectAltName = @SubjectAlternativeName
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:d7:ef:3f:0f:50:b6:1a:43:2c:90:77:82:01:2a:
...略
5b:67:11:4c:b2:f2:51:3a:7d:77:1a:9d:cf:0e:86:
da:f7
Exponent: 65537 (0x10001)
Attributes:
(none)
Requested Extensions:
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
3d:3a:d4:78:81:1f:fa:29:15:6a:67:2d:6c:92:42:7f:4c:fe:
...略
01:c0:cc:f4:16:5f:d8:2e:60:e4:3e:94:e1:6e:18:8f:b3:a8:
a8:93:71:06
```
然后我们再创建一个 `x.com.crt.ini` 文件,保存以下内容,**其中SubjectAlternativeName跟上面的保持一致**
```ini
[ server_cert ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName=@SubjectAlternativeName
[ SubjectAlternativeName ]
DNS.1 = *.x.com
```
> 同样也可以多个
## 签发证书
```ini
openssl x509 \
-in x.com.csr \
-req \
-CA ca.crt \
-CAkey ca.key \
-CAserial ca.srl \
-CAcreateserial \
-extfile x.com.crt.ini \
-extensions server_cert \
-copy_extensions copyall \
-days 360 -out x.com.crt
---
Certificate request self-signature ok
subject=C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com, subjectAltName = @SubjectAlternativeName
```
> `extensions server_cert` 与`x.com.crt.ini`的标签保持一致
在以上过程中,`x.com.ini` 和 `x.com.csr` 是申请证书的客户(比如网站站长、应用开发者)生成,`x.com.crt.ini` 是签发证书的 CA 生成,`x.com.crt` 也是 CA 生成。
## 查看证书
```ini
openssl x509 -in x.com.crt -noout -text
---
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
5b:3e:9f:d1:7d:8f:f2:ab:18:ba:fa:1d:d1:65:ac:4e:40:f2:e3:ac
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com
Validity
Not Before: Jan 12 09:49:16 2024 GMT
Not After : Jan 6 09:49:16 2025 GMT
Subject: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com, subjectAltName = @SubjectAlternativeName
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:d7:ef:3f:0f:50:b6:1a:43:2c:90:77:82:01:2a:
...略
da:f7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Key Identifier:
AC:41:8A:AD:CB:6C:D5:68:E9:B7:59:F2:4B:E5:EF:F5:DA:50:49:C4
X509v3 Authority Key Identifier:
keyid:51:27:75:BE:3E:24:AE:A5:93:C7:1C:DE:F8:23:FB:7F:4D:BF:53:34
DirName:/C=CN/ST=Beijing/L=Beijing/O=LocalOrganizationName/OU=IT/CN=Homelab Root CA/emailAddress=admin@example.com
serial:60:9A:7A:BA:8C:98:9B:F8:1A:DE:46:C4:0C:05:0C:7F:B2:B8:C9:AB
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Data Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Subject Alternative Name:
DNS:*.x.com
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
05:8e:3f:dc:a5:a8:f8:7b:ac:74:6a:c3:c7:b3:f0:33:31:ca:
...略
91:f6:40:0e
```
会看到这里已经有了签名值,它的 X509v3 Authority Key Identifier 刚好就是 CA 的 X509v3 Subject Key Identifier它的 Public Key Modulus 和 CSR 里面的也一样。
## 验证证书
```ini
openssl verify --show_chain -CAfile ca.crt x.com.crt
---
x.com.crt: OK
Chain:
depth=0: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com, subjectAltName = @SubjectAlternativeName (untrusted)
depth=1: C = CN, ST = Beijing, L = Beijing, O = LocalOrganizationName, OU = IT, CN = Homelab Root CA, emailAddress = admin@example.com
```
至此证书生成及颁发已经完成
# 安装根证书
在整个文章中,根证书是`ca.crt`下载到设备上在安装即可。
以windows为例直接双击打开即可安装
![](https://static.lianglianglee.com/2024/01/a134652335648d6ae317be397ddcca45.png)
这里可以选择任意存储
# 配置域名证书
以nginx为例
```ini
server {
listen [::]:1234 ssl http2;
gzip off;
server_name x.com;
ssl_certificate /etc/nginx/certs/x.com.crt;
ssl_certificate_key /etc/nginx/certs/x.com.key;
location / {
add_header Content-Type "text/html; charset=UTF-8";
return 200 "Hello, World!";
}
}
```
`ssl_certificate``ssl_certificate_key` 的值改为证书和私钥的实际路径。
执行 `sudo nginx -t` 测试配置有效性,执行 `sudo nginx -s reload` 更新配置。
在本地 hosts 配置域名解析,把 `x.com` 解析到服务器的IP地址这个在不同操作系统上做法不同。
## 验证
以 https scheme 加端口的方式在浏览器访问,`https://x.com`
![](https://static.lianglianglee.com/2024/01/2ca5b19e09cad661ba0578ebd1ed610e.png)
# 总结和后续
我们介绍了一种创建自签 CA 证书的方式,并且介绍了如何使用 openssl 命令行工具创建和签发自己的证书。自签证书的好处是时效性和低成本,我们不需要有自己的服务器或者 Web 虚拟主机空间,也不需要购买域名,也不需要花时间等待 CA 做验证和恢复。
这种自签证书适用于内网 (intranet),尤其是部署安装根 CA 证书的成本很低的情形,安装了根证书后,后续所有由该根证书签发的证书都可以被系统自动信任。
TLS 可以自动使得上层的应用层服务自动地获得端到端的安全性:**1数据完整性2保密性3真实性**,因此许多应用软件都已提供了对 TLS 的支持,包括最常见的浏览器、数据库命令行工具、远程桌面软件、常驻程序的后台管理界面等。我们可以给每一个这样的服务都签发 TLS 证书,而在终端设备上只需添加信任一次根证书,从而以低成本的方式获得信息安全性提高以及更好的隐私保障。

View File

@ -1,8 +1,6 @@
---
title: MySQL超大表删除数据 title: MySQL超大表删除数据
tags: [] tags: []
categories: [] categories: []
abbrlink: 8ff92769
date: 2023-09-12 16:10:34 date: 2023-09-12 16:10:34
--- ---
# 背景 # 背景

View File

@ -1,8 +1,6 @@
---
title: MySQL引擎介绍 title: MySQL引擎介绍
tags: [] tags: []
categories: [] categories: []
abbrlink: fcfd18c1
date: 2022-04-04 22:44:48 date: 2022-04-04 22:44:48
--- ---
# 引擎是什么? # 引擎是什么?

View File

@ -1,10 +1,8 @@
---
title: MySQL 相关知识汇总 title: MySQL 相关知识汇总
categories: [] categories: []
tags: tags:
- MySQL - MySQL
date: '2023-04-04T13:00:07.258Z' date: '2023-04-04T13:00:07.258Z'
abbrlink: a3556bbe
--- ---
# 1. 简介 # 1. 简介

View File

@ -1,207 +0,0 @@
---
title: 在公司无感访问家里的服务
tags: []
categories: []
abbrlink: 6adf908a
date: 2024-01-11 09:05:48
---
# 简述
家里有一台ALL in Boom跑了一些服务在家里因为可以控制DNS可以无感访问在公司内就没办法使用这些服务了所以需要一种方式在外可以访问家里的服务并且在常用环境做到低延迟访问
想法如下:
![](https://static.lianglianglee.com/2024/01/ea2ce6a84ec56d16f05659d95a24818b.png)
**家庭环境中**由于可以控制DNS直接在Linux主机部署一个Nginx然后修改路由器的域名映射将一些自己的域名直接解析到主机上。
**其他环境中**使用CloudFlare的tunnel提供内网穿透及域名解析服务
**公司环境中**因为个人经常访问如果每次都经过cloudFlare就太慢了所以需要用一些手段加速访问。方案是frp穿透到公网办公电脑用nginx代理到frp端口加速访问这样延迟大大降低。
> 为什么将clash单独列出来是因为host文件无法生效需要对clash做一些改动
**域名相关**
域名使用两套
xxx.com 这个是我自购的域名
xxx.net 这个是虚构的域名,只存在局域网中
# 家庭环境
## 家庭内环境介绍:
路由器使用刷机路由自带frp
Linux主机由PVE虚拟化而来固定IP跑各种docker服务
家庭电脑:无特殊配置,仅需连接到路由器
## 路由器配置
域名配置使用了OpenWrt的主机名配置将需要的域名指向Linux主机
> 每个路由器配置不同
## Linux主机配置
linux主机只需要配置一个nginx代理即可。
nginx我使用的[nginx proxy manager](https://nginxproxymanager.com/),上手简单,且可以浏览器管理。
使用docker-compose部署
```yaml
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:2.10.4'
restart: unless-stopped
ports:
- '80:80'
- '84:81'
volumes:
- ./data:/data
healthcheck:
test: ["CMD", "/bin/check-health"]
interval: 10s
timeout: 3s
```
拉起容器后,可以使用 ip:84 修改一下用户名等信息,默认用户名密码:`admin@example.com/changeme`
### 配置域名代理
代理服务的端口即可
![](https://static.lianglianglee.com/2024/01/5b02300d1df32d5f8925363e94f33105.png)
## 测试访问
使用接入路由器的任意主机,访问这些域名,看是否能访问到
# 公网环境
公网环境需要做以下准备:
1. 自购域名并迁移到cloudflare
2. 创建一个tunnel隧道
相关文档:
* <https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/>
**tunnel国内访问速度极慢本方法只用于紧急访问正常情况下基本无法使用**
## 运行tunnel隧道
在页面创建完成后会给你部署客户端的命令这里我是用docker创建
![](https://static.lianglianglee.com/2024/01/07690de58d1c280eb668739210d28df9.png)
运行完成后,就可以看到客户端了,即完成了客户端的部署
## 配置隧道
进入隧道详情,公共主机名,添加主机名
![](https://static.lianglianglee.com/2024/01/72601465275b0e3e44f8a53d614eab20.png)
以其中的一个域名为例
subdomain子域名比如blog.xxx.comblog就是子域名
domain域名这里选择你迁移到cloudflare的域名
service→Type什么协议
url从隧道客户端访问应该用什么样的IP和端口
![](https://static.lianglianglee.com/2024/01/aaf9f5464f47d443827545b9fc1a4060.png)
创建完成后,等待几分钟,即可访问
# 办公环境
公司设置是为了加速访问所以直接通过frp访问
## 暴漏服务
因为有一台云上的Linux主机所以对我来说最快的方式是使用frp将服务暴漏出来然后通过ip:port访问服务。
> frp部署本次忽略可自行搜索教程
frp只用暴漏家内的nginx端口即可。也就是80端口不用一个一个将服务暴漏出来。
## Nginx配置
nginx配置的模板如下
因为这里只是代理作用使用HTTP代理会有各种各样的配置直接用TCP代理能简化配置流程
```ini
stream {
log_format proxy '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /Nginx/logs/tcp.log proxy ;
#将12345端口转发到192.168.1.23的3306端口
server {
listen 80;
proxy_connect_timeout 5s;
proxy_timeout 3600s;
proxy_pass xxx.xxx.xxx.xxx:port; # 替换成自己的ip,端口
}
}
```
修改`nginx/conf/nginx.conf`这里直接使用TCP代理即可
## Host配置
windows为例用管理员模式修改`C:\Windows\System32\drivers\etc\hosts`文件
增加以下内容
```ini
127.0.0.1 outline.lianglianglee.com
127.0.0.1 gitea.lianglianglee.com
127.0.0.1 s3.lianglianglee.com
127.0.0.1 s3-admin.lll.net
```
修改完成后,保存
> 如遇无法保存,可以把文件复制出来,改动后再复制进去
在浏览器打开配置的域名在控制台看目标地址及端口是否是本地的nginx端口
![](https://static.lianglianglee.com/2024/01/e1d4f9bef76c8478ad6c3f4b3d7e13c6.png)
# 杂项
## clash和host不兼容的问题
办公电脑配置完成后浏览器无法访问但是使用curl又可以访问。
顺其自然打开了浏览器的控制台,发现请求的竟然是`127.0.0.1:7890`端口走的clash所以无法访问
进入clash的`Settings`/`System Proxy`/`Bypass Domin/IPNet`/`Edit`
将自定义的域名加进去即可
```ini
- outline.lianglianglee.com
- gitea.lianglianglee.com
- s3.lianglianglee.com
- s3-admin.lll.net
```
重启clash即可访问到域名

View File

@ -1,8 +1,6 @@
---
title: TrueNAS成型记 title: TrueNAS成型记
tags: [] tags: []
categories: [] categories: []
abbrlink: d7671edf
date: 2023-04-06 15:05:48 date: 2023-04-06 15:05:48
--- ---
# 背景 # 背景

View File

@ -1,353 +0,0 @@
---
title: Outline部署教程
tags: []
categories: []
abbrlink: 9c50151f
date: 2024-01-08 11:28:22
---
# 摘要
因为日常需要写一些自己的学习笔记文章等因此需要一个软件用于记录和展示。市面上有很多可用的产品比如notion语雀飞书等等还有相当一部分可以私有化部署的比如obsidian思源笔记typora等等都可以本地存储。这些唯一的问题是跨设备需要全量同步数据对我来说不是很适合。
## 期望的软件
- **纯Web应用**。设备只需要一个浏览器就可以阅读并编辑所以内容
- **可私有化部署**。作为程序员,数据还是掌握在自己手中比较好
- **占用资源小**。因为是跑在CPU及内存都惨不忍睹的NAS中的服务所以尽量占用资源小
- **支持分享**。偶尔会把文章分享给朋友及同事,能不登陆查看文章。
综合以上期望最后发现一个国内用户比较少的outline。https://www.getoutline.com/
# 介绍
在其github上第一句话是
> *使用 React 和 Node.js 为您的团队构建的快速、协作、知识库。*
其目标是协作的知识库官网介绍中也是着重介绍协作的功能。使用前端技术栈编写界面简洁提供SASS版本灭月最少10刀。我选择私有化部署
查看其部署文档,我只能说有,但不多。那就抛弃官网,自己摸索吧。
## 依赖
根据其提供的env配置文件大概需要以下组件
- PostgreSQL(v12+)
- Redis(v4+)
- S3存储非必须
- 身份认证工具
外国佬的东西,全程手动,什么都要自己准备。
## 选型
**附件存储**outline提供了两种选择类S3存储或本地存储。这里选择minio
**身份认证程序**outline没有提供登录模块需要集成第三方的登录。我这里选择使用Gitea自带的Oauth2
------
接下来按照步骤一点一点部署所有组件都使用docker-compose部署
## 域名规划
这里只表述前缀
- **s3**S3对象存储
- **s3-admin**Minio控制台
- **gitea**Gitea
- **outline**outline的主服务
## 加速访问
因为一般都是内网访问没必要走一圈公网所以这里在路由器配置解析直接把域名解析到NAS。由NAS的Nginx提供服务
# PostgreSQL&Redis&Minio
这里就直接提供docker-compose的文件。
**注意事项**
- PostgreSQL需要提前创建数据库
- Minio需要创建一个匿名访问用于用户头像的读取
## PostgreSQL
因为文件读写权限的问题且都是内网访问这里用privileged开放了docker的用户权限实际生产不建议使用
```yaml
version: '3'
services:
postgres:
image: postgres:13-alpine
container_name: postgres-13
ports:
- 5432:5432
environment:
- POSTGRES_PASSWORD=password # feel free to change the password
volumes:
- ./postgresql/data:/var/lib/postgresql/data # persist postgres data to ~/postgres/data/ on the host
privileged: true
cpus: 2
mem_limit: 512m
```
## Redis
```yaml
version: '3'
services:
redis:
image: redis:4.0.1
container_name: redis
volumes:
- ./datadir:/data
- ./conf/redis.conf:/usr/local/etc/redis/redis.conf
- ./logs:/logs
command: redis-server --requirepass password
ports:
- 6379:6379
```
## Minio
```yaml
version: "3.7"
services:
minio:
image: "quay.io/minio/minio:RELEASE.2024-01-01T16-36-33Z"
ports:
- "9000:9000"
- "9001:9001"
volumes:
- "./minio/data1:/data1"
- "./minio/data2:/data2"
- "./minio:/data"
command: server --console-address ":9001" http://minio/data{1...2}
environment:
- MINIO_ROOT_USER=admin
- MINIO_ROOT_PASSWORD=password
```
进入控制台创建BucketAccessKey
**需要添加一个匿名访问策略,用于头像访问**
![](https://static.lianglianglee.com/2024/01/b8c1dee5eb74cbbfb864e2e2f196891f.png)
# 身份认证程序
身份认证程序使用的Gitea
```yaml
version: "3"
services:
server:
image: gitea/gitea:1.19.3
container_name: gitea
environment:
- GITEA__database__DB_TYPE=mysql
- GITEA__database__HOST=xxx.xxx.xxx.xxx:3306
- GITEA__database__NAME=gitea
- GITEA__database__USER=root
- GITEA__database__PASSWD=password
restart: always
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3002:3000"
- "222:22"
```
gitea使用了MySQL作为数据存储服务
## 创建Oauth2应用
以管理员账号登录gitea后进入管理后台应用tab页
![](https://static.lianglianglee.com/2024/01/49d62f29b251c7fa0aab8e62a1b752e6.png)
重定向URL是outline的地址这里替换成outline的域名或者IP:端口
> http://xxx.xxx.xxx/auth/oidc.callback
创建完成后会生成一堆客户端ID和密钥
![](https://static.lianglianglee.com/2024/01/ccdf3707165be5f883d7c8cbc90faa67.png)
客户端ID和密钥先找个地方记下。
# Outline部署
Outline因为太多的配置项这里使用env文件处理官方的env文件链接如下
https://github.com/outline/outline/blob/main/.env.sample
## 配置
env文件分为几大类
- 应用的加密配置
- PostgreSQLRedis配置
- 应用的域名及端口配置
- 存储配置
- 身份认证配置
- 邮箱配置
- 其他
```ini
# REQUIRED
NODE_ENV=production
# Generate a hex-encoded 32-byte random key. You should use `openssl rand -hex 32`
# in your terminal to generate a random value.
SECRET_KEY=d1020471380935f0053864173d8178578910ab9331a434aa1e4ec20ae6a8bb47
# Generate a unique random key. The format is not important but you could still use
# `openssl rand -hex 32` in your terminal to produce this.
UTILS_SECRET=d1020471380935f0053864173d8178578910ab9331a434aa1e4ec20ae6a8bb47
# 数据库配置
DATABASE_URL=postgres://postgres:password@xxx.xxx.xxx:5432/outline
DATABASE_URL_TEST=postgres://postgres:password@xxx.xxx.xxx:5432/outline-test
DATABASE_CONNECTION_POOL_MIN=
DATABASE_CONNECTION_POOL_MAX=
# 关闭SSL模式
PGSSLMODE=disable
# Redis配置
REDIS_URL=redis://:ll.941107@xxx.xxx.xxx:6379
# Outline的域名及端口
URL=http://outline.xxxx.com
PORT=3004
# S3配置
AWS_ACCESS_KEY_ID=YfIfejBwr2ckKJ4W9Dew
AWS_SECRET_ACCESS_KEY=mqpSPul28PoRs7T3TyEABUTT9zbz1ctcvT277qg1
AWS_REGION=cn-homelab
# AWS_S3_ACCELERATE_URL=
AWS_S3_UPLOAD_BUCKET_URL=http://s3.xxxx.com
AWS_S3_UPLOAD_BUCKET_NAME=outline-blob
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
# 附件存储方式S3或者local
FILE_STORAGE=s3
# 身份认证服务的各种URL
# Redirect URI is https://<URL>/auth/oidc.callback
OIDC_CLIENT_ID=c49f442d-5c63-4394-8a56-78256c502b04
OIDC_CLIENT_SECRET=gto_v5ygxr3ym4a2w4tm3vjwebjr2tokr7jwjoob2zmh7swsq6h6jkda
OIDC_AUTH_URI=http://gitea.xxxx.com/login/oauth/authorize
OIDC_TOKEN_URI=http://gitea.xxxx.com/login/oauth/access_token
OIDC_USERINFO_URI=http://gitea.xxxx.com/login/oauth/userinfo
# Specify which claims to derive user information from
# Supports any valid JSON path with the JWT payload
OIDC_USERNAME_CLAIM=name
# Display name for OIDC authentication
OIDC_DISPLAY_NAME=Gitea
# Space separated auth scopes.
OIDC_SCOPES=openid email name
# OPTIONAL
# If using a Cloudfront/Cloudflare distribution or similar it can be set below.
# This will cause paths to javascript, stylesheets, and images to be updated to
# the hostname defined in CDN_URL. In your CDN configuration the origin server
# should be set to the same as URL.
# CDN_URL=
# Auto-redirect to https in production. The default is true but you may set to
# false if you can be sure that SSL is terminated at an external loadbalancer.
FORCE_HTTPS=false
# Have the installation check for updates by sending anonymized statistics to
# the maintainers
ENABLE_UPDATES=false
# 应用启动几个进程因为只有我一个人访问设置1即可。按照内存/512M设置数量
WEB_CONCURRENCY=1
# 最大导入大小
MAXIMUM_IMPORT_SIZE=5120000
# You can remove this line if your reverse proxy already logs incoming http
# requests and this ends up being duplicative
DEBUG=http
# Configure lowest severity level for server logs. Should be one of
# error, warn, info, http, verbose, debug and silly
LOG_LEVEL=debug
# 邮箱的配置
SMTP_HOST=smtp.sina.com
SMTP_PORT=465
SMTP_USERNAME=xxxx@sina.com
SMTP_PASSWORD=xxxxx
SMTP_FROM_EMAIL=xxxx@sina.com
SMTP_REPLY_EMAIL=xxxx@sina.com
# SMTP_TLS_CIPHERS=
SMTP_SECURE=true
# 默认语言,这里选择中文
DEFAULT_LANGUAGE=zh_CN
# Optionally enable rate limiter at application web server
RATE_LIMITER_ENABLED=true
# Configure default throttling parameters for rate limiter
RATE_LIMITER_REQUESTS=1000
RATE_LIMITER_DURATION_WINDOW=60
# Enable unsafe-inline in script-src CSP directive
# Setting it to true allows React dev tools add-on in
# Firefox to successfully detect the project
DEVELOPMENT_UNSAFE_INLINE_CSP=false
```
如果您使用的身份认证程序不一样则按照其文档的URL填写以下参数
- OIDC_AUTH_URI认证接入点
- OIDC_TOKEN_URI访问token接入点
- OIDC_USERINFO_URI用户详情
- OIDC_USERNAME_CLAIM简单来说用什么作为用户名从OIDC_SCOPES选择
- OIDC_SCOPES申请的权限要根据身份认证程序确定有哪些权限
## 部署
```ini
version: "3.2"
services:
outline:
image: docker.getoutline.com/outlinewiki/outline:0.74.0
env_file: .env
ports:
- "3004:3004"
volumes:
- ./data:/var/lib/outline/data
```
注意:
- .env就是上面说的配置文件需要跟docker-compose.yml同目录
- 容器内的3004是env文件的PORT配置
启动完成后稍等片刻即可访问http://ip:3004
# 使用手册
https://docs.getoutline.com/s/guide

View File

@ -1,8 +1,6 @@
---
title: PVE复制CentOS导致网卡启动失败的问题 title: PVE复制CentOS导致网卡启动失败的问题
tags: [] tags: []
categories: [] categories: []
abbrlink: 98c423c7
date: 2023-11-30 14:42:03 date: 2023-11-30 14:42:03
--- ---

View File

@ -1,11 +1,9 @@
---
title: 读《贪婪的多巴胺》第一章 title: 读《贪婪的多巴胺》第一章
tags: tags:
- 读书 - 读书
- 杂项 - 杂项
categories: categories:
- 读书 - 读书
abbrlink: 37dc4048
date: 2023-06-17 19:45:16 date: 2023-06-17 19:45:16
--- ---

View File

@ -1,8 +1,6 @@
---
title: 个人小网站的升级之路 title: 个人小网站的升级之路
tags: [] tags: []
categories: [] categories: []
abbrlink: 7d78d6bb
date: 2023-04-13 13:58:25 date: 2023-04-13 13:58:25
--- ---
# 背景 # 背景

View File

@ -1,8 +1,6 @@
---
title: 油猴脚本保存51CTO为HTML文件 title: 油猴脚本保存51CTO为HTML文件
tags: [] tags: []
categories: [] categories: []
abbrlink: 4d33d521
date: 2023-11-12 14:11:46 date: 2023-11-12 14:11:46
--- ---
# 背景 # 背景

View File

@ -1,8 +1,6 @@
---
title: 技术方案模板 title: 技术方案模板
tags: [] tags: []
categories: [] categories: []
abbrlink: '16911e78'
date: 2023-03-04 22:39:28 date: 2023-03-04 22:39:28
--- ---

View File

@ -1,8 +1,6 @@
---
title: 使用Cloudflare做HTTP内网穿透 title: 使用Cloudflare做HTTP内网穿透
tags: [] tags: []
categories: [] categories: []
abbrlink: 383a561d
date: 2023-12-11 11:39:18 date: 2023-12-11 11:39:18
--- ---
# 背景 # 背景

View File

@ -1,8 +1,6 @@
---
title: 使用油猴脚本保存极客时间文章 title: 使用油猴脚本保存极客时间文章
tags: [] tags: []
categories: [] categories: []
abbrlink: 62a77eea
date: 2023-08-03 16:58:17 date: 2023-08-03 16:58:17
--- ---
# 背景 # 背景

@ -1 +1 @@
Subproject commit e0fbe04d7d89626a2e700ffdc47f4116e925f9ca Subproject commit afee0b2ba54730328d1a972d4ab13e9af61f3ce8