简介 前面讲解了如何自托管开源的远程工具Rustdesk，但是我们使用的客户端还是官方的，每次都需要自己填写自己的中继服务器，KEY等，比较麻烦 这次我们自己编译自己的客户端，把我们的中继服务器写入客户端里面，打开就可以使用 本文章有可能出现图不对版的情况，主要是图片太多了又是晚上写的，脑袋有点混乱，如有不懂的地方可以留言 fork项目 我们需要fork两个项目，一个是rustdesk的项目，另外一个是rustdesk的子模块项目 rustdesk项目地址：https://github.com/rustdesk/rustdesk rustdesk子模块项目地址：https://github.com/rustdesk/hbb_common fork rustdesk项目 打开rustdesk的项目地址，然后点击右上角的Fork 点击绿色的Crtate Fork按钮 fork rustdesk子模块项目 也是一样的，打开项目地址，然后点击右上角的fork 点击绿色的Crtate Fork按钮 修改指向子模块的链接 进入fork的rustdesk的仓库，点击.gitmodules打开文件 点击右上角的铅笔图标，进入编辑模式 把url这一行的链接换成我们刚刚fork的子模块的仓库链接 点击右上角的绿色的Commit changes...保存 重新备注一下，然后点击绿色的Commit changes保存 修改api、服务器地址、服务器key 修改服务器地址和服务器key 进入fork好的子模块仓库，点击src打开目录 点击config.rs打开文件 点击右上角的铅笔图标，进入文件的编辑模式 按键盘【Ctrl】+【F】搜索下面内容 rs-ny.rustdesk.com 把搜索到的网址替换成为自己的服务器地址或者域名 把下面的key替换成自己的key，然后点击右上角绿色的Commit changes...保存 填写备注，然后点击绿色的Commit changes保存 点击右上角的ID打开修改详情 然后把地址栏上的hash值复制记录下来，待会有用 修改api地址 返回克隆好的rustdesk仓库，点击进入src目录 点击打开common.rs文件 点击右上角的铅笔图标，进入编辑模式 按键盘【Ctrl】+【F】搜索admin 把这个网址替换成自己的服务器的api地址，然后点击右上角绿色的Commit changes...保存 填写备注，然后点击绿色的Commit changes保存 创建github的token 点击github的头像，选择Settings 滑倒底部，点击Developer settings 点击Personal access tokens下的Tokens (classic) 点击 Generate new token下的Generate new token (classic) Note随便填写，然后勾选repo 滑倒底部，点击Generate token 点击生成的token旁边的复制按钮复制，然后保存到记事本之类的地方，待会有用 推送子模块更新文件 进入fork好的rustdesk仓库 然后复制下面代码到记事本中，方便修改 // 替换为您的实际信息 const owner = 'Github用户名'; const repo = '仓库名称'; const submodulePath = 'libs/hbb_common'; const newCommitHash = '刚刚记录的hash值'; const branch = 'master'; async function updateSubmodule() { try { // 获取 GitHub Token const token = prompt('请输入您的GitHub Personal Access Token (需要repo权限):'); if (!token) { alert('需要Token才能继续'); return; } // 注意：这里的反引号是关键 const headers = { 'Authorization': `token ${token}`, 'Content-Type': 'application/json', 'Accept': 'application/vnd.github.v3+json' }; console.log('1. 获取分支引用...'); const refResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/refs/heads/${branch}`, { headers: headers }); if (!refResponse.ok) { throw new Error(`获取分支引用失败: ${refResponse.status} ${refResponse.statusText}`); } const refData = await refResponse.json(); const currentCommitSha = refData.object.sha; console.log('当前提交SHA:', currentCommitSha); console.log('2. 获取提交对象...'); const commitResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/commits/${currentCommitSha}`, { headers: headers }); if (!commitResponse.ok) { throw new Error(`获取提交对象失败: ${commitResponse.status} ${commitResponse.statusText}`); } const commitData = await commitResponse.json(); const treeSha = commitData.tree.sha; console.log('3. 创建新树...'); const treeResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees`, { method: 'POST', headers: headers, body: JSON.stringify({ base_tree: treeSha, tree: [ { path: submodulePath, mode: '160000', // 子模块模式 type: 'commit', sha: newCommitHash } ] }) }); if (!treeResponse.ok) { const errorText = await treeResponse.text(); throw new Error(`创建树失败: ${treeResponse.status} - ${errorText}`); } const treeData = await treeResponse.json(); console.log('4. 创建新提交...'); const newCommitResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/commits`, { method: 'POST', headers: headers, body: JSON.stringify({ message: `Update ${submodulePath} submodule to ${newCommitHash.substring(0, 8)}`, tree: treeData.sha, parents: [currentCommitSha] }) }); const newCommitData = await newCommitResponse.json(); console.log('5. 更新分支引用...'); const updateRefResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/refs/heads/${branch}`, { method: 'PATCH', headers: headers, body: JSON.stringify({ sha: newCommitData.sha, force: false }) }); if (!updateRefResponse.ok) { throw new Error('更新引用失败'); } alert(`✅ 子模块更新成功！\n新提交: ${newCommitData.sha.substring(0, 8)}`); } catch (error) { console.error('错误:', error); alert(`❌ 更新失败: ${error.message}`); } } updateSubmodule(); 需要修改2、3、5行 第二行改成自己的github的用户名 第三行改成仓库名称 第五行改成刚刚复制的hash值 下面是我修改好后的代码 // 替换为您的实际信息 const owner = 'xiaowen-king1'; const repo = 'rustdesk'; const submodulePath = 'libs/hbb_common'; const newCommitHash = 'e410cc8bae62f7b761e30deac737839fbff598be'; const branch = 'master'; async function updateSubmodule() { try { // 获取 GitHub Token const token = prompt('请输入您的GitHub Personal Access Token (需要repo权限):'); if (!token) { alert('需要Token才能继续'); return; } // 注意：这里的反引号是关键 const headers = { 'Authorization': `token ${token}`, 'Content-Type': 'application/json', 'Accept': 'application/vnd.github.v3+json' }; console.log('1. 获取分支引用...'); const refResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/refs/heads/${branch}`, { headers: headers }); if (!refResponse.ok) { throw new Error(`获取分支引用失败: ${refResponse.status} ${refResponse.statusText}`); } const refData = await refResponse.json(); const currentCommitSha = refData.object.sha; console.log('当前提交SHA:', currentCommitSha); console.log('2. 获取提交对象...'); const commitResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/commits/${currentCommitSha}`, { headers: headers }); if (!commitResponse.ok) { throw new Error(`获取提交对象失败: ${commitResponse.status} ${commitResponse.statusText}`); } const commitData = await commitResponse.json(); const treeSha = commitData.tree.sha; console.log('3. 创建新树...'); const treeResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees`, { method: 'POST', headers: headers, body: JSON.stringify({ base_tree: treeSha, tree: [ { path: submodulePath, mode: '160000', // 子模块模式 type: 'commit', sha: newCommitHash } ] }) }); if (!treeResponse.ok) { const errorText = await treeResponse.text(); throw new Error(`创建树失败: ${treeResponse.status} - ${errorText}`); } const treeData = await treeResponse.json(); console.log('4. 创建新提交...'); const newCommitResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/commits`, { method: 'POST', headers: headers, body: JSON.stringify({ message: `Update ${submodulePath} submodule to ${newCommitHash.substring(0, 8)}`, tree: treeData.sha, parents: [currentCommitSha] }) }); const newCommitData = await newCommitResponse.json(); console.log('5. 更新分支引用...'); const updateRefResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/refs/heads/${branch}`, { method: 'PATCH', headers: headers, body: JSON.stringify({ sha: newCommitData.sha, force: false }) }); if (!updateRefResponse.ok) { throw new Error('更新引用失败'); } alert(`✅ 子模块更新成功！\n新提交: ${newCommitData.sha.substring(0, 8)}`); } catch (error) { console.error('错误:', error); alert(`❌ 更新失败: ${error.message}`); } } updateSubmodule(); 返回github的我们fork好的rustdesk仓库，然后按快捷键【Ctrl】+【Shift】+【i】打开浏览器控制台 把修改好后的代码粘贴进去回车执行，根据提示输入刚刚生成的token，然后点击确定 提示成功后完成，点击确定 开始编译 点击顶部的Actions 点击绿色的Workflows aren’t being run on this forked repository 点击侧边栏的Show more workflows... 点击Flutter Nightly Build 点击Enable workflow 点击Run workflow下的绿色Run workflow 接下来就是漫长的等待了，预计一个半小时到两个小时可以编译完成 下载编译后的文件 打开rustdesk项目地址，点击顶部的标签图标 点击nightly进入就可以看到编译好的包了
简介 前几天把博客更新到1.3.0的时候崩了，数据库有问题，只能重建数据库 我选择的是直接使用命令重建数据库 重建数据库的前提是你备份有数据库文件 第一步 进入mysql mysql -u root -p 然后输入数据库的root密码进入 第二步 查询数据库 SHOW DATABASES; 然后删除数据库 DROP DATABASE ersansi_top; 创建数据库 CREATE DATABASE ersansi_top DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; 退出mysql EXIT; 导入数据库 接下来就是把备份的数据库导入 进入备份数据库所在目录 cd /root/mysql-bak-up 然后执行导入操作 mysql -u ersansi_top -p ersansi_top < ersansi_top-20260121-000038.sql 如果博客使用的这个数据库用户名和密码无权限导入，则参考《Centos7配置mysql远程访问及常用命令》进行授权操作
简介 我们常用的远程工具有向日葵，todesk等，虽然是可以免费使用，但是是有限制的，自己部署的RustDesk就没有任何限制了，但是前提是你要有自己的服务器 如果你不是经常使用远程桌面工具，或者是没有自己的服务器，我感觉就没必要自己部署，毕竟租一个服务器一个月最低的也要二三十块，都可以开通各个大厂的远程工具的会员了 如果想要所有数据走自己的服务，不想数据走其他厂商的服务，或者是恰好有服务器，那么可以自己部署一个玩玩 第一步：安装docker和docker compose 这里我使用的是docker部署 如果你的服务器上已经安装了docker和docker compose，那么就可以跳过这一步 如果你的服务器还没有安装，那么安装教程可以查看我之前的文章《从零开始学习Docker--Docker的安装和配置仓库源加速》 第二步：修改配置文件 这里使用到的项目是lejianwen/rustdesk-api，我们使用里面的配置文件来修改就可以 项目地址：https://github.com/lejianwen/rustdesk-api 打开项目地址 滑倒最底下就可以看到docker-compose.yaml文件的内容了 下面是这个配置文件的解释 networks: rustdesk-net: external: false services: rustdesk: ports: # 映射21114端口TCP协议：用于网页控制台 - 21114:21114 # 映射21115端口TCP协议：用于NAT类型测试 - 21115:21115 # 映射21116端口TCP协议：用于ID注册和星跳服务（UDP），以及TCP打动和连接服务（TCP）。需要同时启用TCP和UDP - 21116:21116 # 映射 21116 端口 (UDP)：用于 ID 注册和心跳服务。 - 21116:21116/udp # 映射 21117 端口 (TCP)：用于中继服务。 - 21117:21117 # 映射 21118 端口 (TCP)：用于支持网页客户端。 - 21118:21118 # 映射 21119 端口 (TCP)：用于支持网页客户端。 - 21119:21119 # 使用的镜像 image: lejianwen/rustdesk-server-s6:latest environment: # 设置中继服务器地址，如果没有域名则是ip地址:端口（http://192.168.99.2:21117）,如果有域名则把ip地址替换成域名，端口保持21117 - RELAY=http://ip地址:21117 # 启用加密模式，1是启用，0是禁用 - ENCRYPTED_ONLY=1 # 是否必须登录才能使用远程，Y是是，N是否 - MUST_LOGIN=N # 时区 - TZ=Asia/Shanghai # 设置ID服务器地址 - RUSTDESK_API_RUSTDESK_ID_SERVER=http://ip或者域名:21116 # 设置中继服务器地址 - RUSTDESK_API_RUSTDESK_RELAY_SERVER=http://ip或者域名:21117 # 设置API服务器地址 - RUSTDESK_API_RUSTDESK_API_SERVER=http://ip或者域名:21114 # API密钥文件路径，保持默认即可 - RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub # JWT 密钥，留空表示不启用 - RUSTDESK_API_JWT_KEY= volumes: # 数据持久化 - /data/rustdesk/server:/data - /data/rustdesk/api:/app/data #将数据库挂载 networks: - rustdesk-net # 容器停止时自动重启，除非手动停止 restart: unless-stopped 上面的配置文件中已经帮我们配置了必须要的东西，我们需要在上面的配置文件中进行修改，大家使用下面配置的时候一定要一项一项的看，只要看到http://ip或域名的就替换成你服务器的ip或者是域名。 networks: rustdesk-net: external: false services: rustdesk: ports: # 映射21114端口TCP协议：用于网页控制台 - 21114:21114 # 映射21115端口TCP协议：用于NAT类型测试 - 21115:21115 # 映射21116端口TCP协议：用于ID注册和星跳服务（UDP），以及TCP打动和连接服务（TCP）。需要同时启用TCP和UDP - 21116:21116 # 映射 21116 端口 (UDP)：用于 ID 注册和心跳服务。 - 21116:21116/udp # 映射 21117 端口 (TCP)：用于中继服务。 - 21117:21117 # 映射 21118 端口 (TCP)：用于支持网页客户端。 - 21118:21118 # 映射 21119 端口 (TCP)：用于支持网页客户端。 - 21119:21119 # 使用的镜像 image: lejianwen/rustdesk-server-s6:latest environment: # 设置中继服务器地址，如果没有域名则是ip地址:端口（http://192.168.99.2:21117）,如果有域名则把ip地址替换成域名，端口保持21117 - RELAY=http://ip或域名:21117 # 启用加密模式，1是启用，0是禁用 - ENCRYPTED_ONLY=1 # 是否必须登录才能使用远程，Y是是，N是否 - MUST_LOGIN=Y # 时区 - TZ=Asia/Shanghai # 设置ID服务器地址 - RUSTDESK_API_RUSTDESK_ID_SERVER=http://ip或域名:21116 # 设置中继服务器地址 - RUSTDESK_API_RUSTDESK_RELAY_SERVER=http://ip或域名:21117 # 设置API服务器地址 - RUSTDESK_API_RUSTDESK_API_SERVER=http://ip或域名 # API密钥文件路径，保持默认即可 - RUSTDESK_API_KEY_FILE=/data/id_ed25519.pub # JWT 密钥，留空表示不启用 - RUSTDESK_API_JWT_KEY= #---------------------------------------------以下为新增---------------------------------------------------------------------------- # 设置 WebSocket 服务器地址 - RUSTDESK_API_RUSTDESK_WS_HOST=http://ip或域名 # JWT 过期时间，留空表示不启用 - RUSTDESK_API_JWT_EXPIRE_DURATION= # 是否启用web-client; 1:启用,0:不启用; 默认启用 - RUSTDESK_API_APP_WEB_CLIENT=1 # 是否开启注册; true, false 默认false - RUSTDESK_API_APP_REGISTER=false # token有效时长 - RUSTDESK_API_APP_TOKEN_EXPIRE=168h # 是否禁用密码登录; true, false 默认false - RUSTDESK_API_APP_DISABLE_PWD_LOGIN=false # 注册用户默认状态; 1 启用，2 禁用, 默认 1 - RUSTDESK_API_APP_REGISTER_STATUS=1 # 验证码触发次数; -1 不启用， 0 一直启用， >0 登录错误次数后启用 ;默认 3 - RUSTDESK_API_APP_CAPTCHA_THRESHOLD=3 # 封禁IP触发次数; 0 不启用, >0 登录错误次数后封禁IP; 默认 0 - RUSTDESK_API_APP_BAN_THRESHOLD=5 # 后台标题 - RUSTDESK_API_ADMIN_TITLE=RustDesk管理 # Web client v2 中是否启用新的在线状态查询方法; 1:启用,0:不启用,默认不启用 - RUSTDESK_API_RUSTDESK_WEBCLIENT_MAGIC_QUERYONLINE=1 #---------------------------------------------以上为新增---------------------------------------------------------------------------- volumes: # 数据持久化 - /opt/rustdesk/data/server:/data - /opt/rustdesk/data/api:/app/data #将数据库挂载 networks: - rustdesk-net # 容器停止时自动重启，除非手动停止 restart: unless-stopped 第三步：创建目录 根据自己的使用习惯创建目录，我习惯是自己安装的东西都放在/opt目录下，我就需要在/opt目录下创建rustdesk目录，rustdesk目录下有data目录和config目录，data目录下面有api目录和server目录 我的目录结构为： / |--opt |--rustdesk |--data | |--api | |--server |--config 第四步：创建docker-compose.yaml文件 进入/opt/rustdesk/config目录，创建一个名称为docker-compose.yaml的文件 然后把我们刚刚第二步修改好的配置文件粘贴进去，然后保存退出 第五步：启动 在config目录使用下面命令启动容器 docker compose up -d 等待拉取镜像完成后启动好后可以使用下面命令查看是否启动 docker ps 这时候其实使用ip加端口或者是域名加端口已经可以访问了 第六步：登录 默认用户名是admin，密码是随机的，我们使用下面命令查看密码 首先使用下面命令查看容器名称 docker ps 然后使用查看日志命令查看容器的日志 docker logs 容器名称 日志里面有一行Admin Password Is:后面就是密码 填写完成后点击登录就可以登录上去了 第七步：配置客户端 客户端项目地址：https://github.com/rustdesk/rustdesk 到项目地址里面下载适合自己的客户端 打开客户端，点击ID右边的三个点 点击【网络】 点击【ID/中继服务器】 按照我们的配置文件找到ID服务器、中继服务器、API服务器的地址填上去，最关键的KEY可以在日志中找到 填写完成后点击确定，然后返回主页，看到底部有就绪两个字就是成功了 配置反向代理（非必须） 我使用了nginx配置了反向代理，同时开启了https 因为每个人使用的nginx面板不一样，还有有的直接不使用面板，纯的nginx，所以这里不详细讲解怎么配置 配置反向代理的思路为以下 一、创建一个空站点 二、修改站点的nginx的配置文件，在配置文件中添加反向代理，证书等 下面是我反向代理的配置文件模板 # ----------------------------------------------------------- # Nginx 反向代理模板 # 支持 WebSocket、IPv6、标准化 Forwarded 头、HTTP→HTTPS # ----------------------------------------------------------- # 处理 WebSocket 升级：如果请求头有 Upgrade，则 Connection 设置为 upgrade，否则 close map $http_upgrade $connection_upgrade { default upgrade; '' close; } # 生成符合 RFC 7239 的标准化 Forwarded 头 map $remote_addr $proxy_forwarded_elem { # IPv4: 直接使用 ~^[0-9.]+$ "for=$remote_addr"; # IPv6: 用 [] 括起来并加引号 ~^[0-9A-Fa-f:.]+$ "for=\"[$remote_addr]\""; # Unix Socket: 无法表示，用 unknown default "for=unknown"; } # 如果请求已带 Forwarded 头，追加；否则新增 map $http_forwarded $proxy_add_forwarded { "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=.*)?(;.*?)*([ \\t]*,.*?)*$" "$http_forwarded, $proxy_forwarded_elem"; default "$proxy_forwarded_elem"; } # ----------------------------------------------------------- # HTTP 服务器：监听 80，自动重定向到 HTTPS # ----------------------------------------------------------- server { listen 80; listen [::]:80; server_name ****.********.top; # 防止 Host 被伪造 if ($host != $server_name) { return 404; } # Let's Encrypt 验证路径，需放行，不跳转 location ~ /.well-known/acme-challenge { proxy_pass http://127.0.0.1:9180; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr:$remote_port; } # 其他所有请求都重定向到 HTTPS location / { return 301 https://$host$request_uri; } } # ----------------------------------------------------------- # HTTPS 服务器：监听 443，反向代理到后端 # ----------------------------------------------------------- server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ****.********.top; # SSL 证书 ssl_certificate /etc/nginx/ssl/****.********.top_P256/fullchain.cer; ssl_certificate_key /etc/nginx/ssl/****.********.top_P256/private.key; # 启用 TLS 1.2 和 TLS 1.3 ssl_protocols TLSv1.2 TLSv1.3; # 使用推荐的加密套件 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; # 防止 Host 被伪造 if ($host != $server_name) { return 404; } # 主业务代理 location / { proxy_pass http://127.0.0.1:21114/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_redirect off; # 常规头 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Forwarded $proxy_add_forwarded; } location ~ /.well-known/acme-challenge { proxy_set_header Host $host; proxy_set_header X-Real_IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr:$remote_port; proxy_pass http://127.0.0.1:9180; } # WebSocket 代理设置 location /ws/id { proxy_pass http://127.0.0.1:21118; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /ws/relay { proxy_pass http://127.0.0.1:21119; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
简介 vaultwarden的前端是可以设置中文的，但是后台和邮件模板是不能直接设置的 官方给了我们自己翻译的方法 既然官方给了教程，那么网上肯定有大佬翻译好了，我们直接拿过来使用就可以了 今天使用到的这个项目大佬还打包了中文的docker镜像，如果感觉自己配置中文麻烦，那么直接切换大佬打包的镜像就可以了 中文项目地址 这里有大佬已经把整个项目翻译成中文了 地址：https://github.com/vlianx/vaultwarden_zh_cn 下载模板 我这里不切换镜像了，直接把大佬的模板配置进去 首先我们打开大佬的项目 然后点击右上角的“Code”，选择“Download ZIP” 然后把下载好的zip压缩包解压出来 上传文件 首先查看我们的docker-compose文件，确定数据持久化的目录 进入我们数据持久化目录 创建一个名称为templates的目录 mkdir templates 然后把我们解压的文件夹里面的vaultwarden_zh_cn-main\src\static\templates目录下的“admin”,“email”,“scss”文件夹上传到我们刚刚在服务器上创建的“templates”文件夹里面 修改变量 打开我们的docker-compose文件，新增一个变量，变量名称为TEMPLATES_FOLDER:，变量的值是docker被映射的数据目录下的templates目录 例如我映射的是 volumes: - /opt/vaultwarden/data/:/data/ 那么新增的这个变量的值就是 /data/templates 完成 修改完成后，重启docker容器，再次进入后台就可以看到是中文的了 但是这个后台管理模板官方给的能翻译的地方不多，聊胜于无吧 发送一个测试邮件，可以看到邮件也是中文的了
简介 vaultwarden是一个开源的密码管理工具，目前这个项目收藏有50.9K，是一个很出名的密码管理工具了 这时候有同学可能会有个疑问，那就是我们的浏览器以及自带密码管理了，还有比较部署这个吗？ 接下来说一下我对这个工具的理解 首先这个是自托管的，也就是意味着数据掌握在自己手里 其次就是实用性，我感觉这个比浏览器自带的密码管理好用多了，浏览器自带的密码管理只能管理你在这个浏览器上使用的密码，一旦你换浏览器了就得导出密码从新导入，使用这个工具就不会有这样的问题，换浏览器后直接安装一个插件即可 然后就是跨端跨设备，使用这个工具你不但可以在电脑上使用，这个工具有移动端，你也可以在移动端上使用，这样你的密码更集中管理，更方便管理 还有一点就是团队使用，这个工具可以建立组织，让同一个组织的人员都可以共同调用密码，这个对于那种一个账号多共享的还是很实用的 项目地址 https://github.com/dani-garcia/vaultwarden 开始部署 这里的部署不止可以使用docker，还可以是二进制文件，但是使用二进制文件需要自己编译，所以我选择使用docker部署，很方便 这里就不重复docker和docker-compose的安装了，如果不会安装的可以参考这篇文章《从零开始学习Docker--Docker的安装和配置仓库源加速》 编写docker-compose文件 首先我们编写docker-compose文件，我们打开项目地址 滑倒下面，这里官方以及给了一个基础的docker-compose文件了，我们只需要在这个基础上修改即可 复制这个文件下来，新建一个记事本，粘贴进去 接下来我们需要修改的地方就三个，一个是变量，一个是数据持久化，还有就是端口 变量 必须变量 首先是变量，这里基础的docker-compose文件里面有一个DOMAIN: "https://vw.domain.tld"变量，这个变量是配置站点根目录 也就是说你的站点的域名的，如果没有域名，使用的ip就直接填写ip即可，但是这里注意的是，如果不是局域网使用建议配置域名和证书，否则你的数据就会以明文传输，意味着你的密码将会在网络上暴露 我这里时在局域网内演示，所以我直接填写ip地址 演示配置其他变量，非必须 这里我在演示一下配置其他变量，这个不是必须的，可以不用配置，都是可以在系统后台管理里面配置的 然后我们在项目地址网上翻，找到官方的变量说明，找到自己需要的变量添加上去 例如我还需要配置邮件服务，用于身份验证和发送忘记密码的时候密码提示 在项目首页找到“Usage”，在里面找到“Wiki”，点击查看详细的说明 我们在右边的导航栏里面找到“Configuration”，里面有一个“SMTP configuration”，点击查看 这里就可以看到官方给的启动示例文件了，-e开头的都是启动变量，我们可以把这个变量直接写入我们的docker-compose文件里面 我们把-e开头的全部复制，粘贴到记事本里面，粘贴的位置在刚刚我们改的ip的那个变量下面 docker-compose文件如果需要注释的话可以时#号开头 然后把前面的-e和后面的\删掉，记得保持缩进和ip那个变量一样 配置管理员 如果你不想直接在docker-compose文件里面配置邮箱等其它配置，那么就需要配置管理员，通过管理员进入系统后台进行配置 我们在右边目录里面找到“Enabling admin page”，点击打开 也是-e开头的，复制到记事本里面 然后把=号后面改成一个你的密码 注意 到这里我们的变量并没有配置完成，有细心的同学可能发现了，官方默认改的DOMAIN: "http://192.168.99.25"这个变量不是=号 是的，这里我们还需要把变量里面的=号换成:（冒号+一个空格），记住，冒号一定要英文的 数据持久化 接下来就是数据持久化了 在官方的配置文件里面其实已经做了数据持久化，但是我还是习惯改成绝对路径 volumes:下面的就是数据持久化 官方的是 - ./vw-data/:/data/ 这里就看自己心情修改了，但是注意的是你只能修改:前面的，后面的不要修改 下面这个是我修改的路径 /opt/vaultwarden/data 端口/地址映射 官方给的配置文件的端口映射是把宿主机的8000端口映射到容器的80端口，这里可改可不改，如果你的服务器的8000端口没有被占用就没必要修改 这里要修改也是只能修改80端口前面的:前面的内容，后面的是不能修改的 下面是我修改后的内容，我把原本的8000端口改成了8080端口 还有就是8080端口前面的地址127.0.0.1，这个就限制了我们只能本机访问，也就是只能服务器自己访问，如果我们做反向代理的话这个不用修改，保持127.0.0.1即可，如果不做反向代理，那么就改成0.0.0.0，允许所有地址访问 创建目录 之前的docker-compose文件我们做了一个绝对路径的数据持久化，我们需要把目录创建好 ssh连接上服务器，执行下面命令，记住，创建的目录一定是你要做数据持久化的目录 mkdir -p /opt/vaultwarden/data 然后我们进入/opt/vaultwarden cd /opt/vaultwarden 在创建一个用于存放docker-compose文件的目录，当然也可以不创建，直接把docker-compose文件扔你记得的地方，看个人习惯来 mkdir config 进入我们创建的config目录 cd config 创建docker-compose.yaml文件 刚刚我们以及在记事本上编辑好docker-compose文件了，现在就需要我们在config目录下使用vi创建一个docker-compose.yaml文件，然后把记事本上的内容粘贴进去 vi docker-compose.yaml 然后按【i】进入编辑模式，把刚刚记事本上的内容粘贴进来 按【esc】编辑模式，输入“:wq”保存并退出 执行部署 在config目录下也就是我们存放docker-compose文件的目录下执行下面命令开始拉取镜像并部署 docker compose up -d 完成部署 看到下面内容就是部署完成了 可以使用下面命令查看是否成功运行，只要看到端口正常就成功运行了 docker ps 用户登录 在浏览器上输入服务器地址加上刚刚我们docker-compose文件里面写的端口号访问，我的是8080端口 这时候你会发现一直在转圈圈 那是因为我们没有配置证书，即使我们在docker-compose里面的DOMAIN: "
简介 上一篇文章说了怎么在netlib.re上注册域名并且托管到CF，但是netlib.re时需要六个月内登录一次的次啊能保活 这篇文章教大家如果使用Github上开源的项目进行自动保活，全程无需人工干预 保活项目地址 Github：https://github.com/eooce/Auto-login-netlib netlib.re保活 进入Github项目地址 然后点击顶部的“Fork”把项目克隆到我们的Github仓库 点击“Create fork” 点击顶部的“Actions” 点击“I understand my workflows, go ahead and enable them” 返回仓库主页 点击顶部的“Settings” 点击左边导航栏的“Secrets and variables” 点击“Actions”，添加变量 点击绿色的“New repository secret” 然后再Name栏填入变量名 ACCOUNTS 下面填入账号和密码，账号密码之间用英文冒号分隔，账号与账号之间英文逗号分隔，例如下面 单账号：账号1:密码1 多账号：账号1:密码1,账号2,密码2 例如我时多账号，我第一个账号名为xxhh，密码为xxhh789987，第二个账号为xxyy，密码为xxyy567890，那么我就应该像下面这样填入 xxhh:xxhh789987,xxyy:xxyy567890 填写完成后点击“Add secret” 下面这样就是添加好了 接下来返回仓库主页 点击顶部的“Actions” 点击“Netlib Keepalive” 点击“Enable workflow”检查配置是否有误 点击“Run workflow” 点击绿色的“Run workflow” 等待一小会，等它弹出下面这个界面 可以点击正在运行的工作流，进去查看 我这里已经运行完成了，我们点击进入 然后点击“Run lognin script”查看结果 这里自动保活就完成了 这个是每30天自动登录一次，也可以自己修改，如果需要自己修改登录天数可以，如果需要修改可以进入.github/workflows目录下修改login.yml文件
简介 现在想要永久免费获取一个域名还是很简单的，但是托管到cf时会有各种问题，如果掌握了正确的姿势，那么也是很简单的，很多永久免费的域名都是托管不到CF的 注意事项 今天我们使用来申请域名的网站是https://www.netlib.re/，但是这个网站有BUG，有个坑，如果你不注意那么你申请到的域名就无法托管到CF，或者侥幸托管上去了但是边缘证书验证不通过，这样的托管也是没用的，即使你删除已经申请的域名从新申请也是不行的，也就是说一旦失败，那么你这个域名将会和CF无缘了，所以一定要紧跟教程一步一步做 这个BUG就是我们申请域名后必须马上把默认的NS修改成CF的，否则等后面是修改不成功的，只要默认NS提交上去了我们就修改不了，这就会导致托管到CF失败。 这个BUG可能作者后续会修复，这个也是不清楚的 第一步：注册netlib.re 打开上面给的网址 点击右上角的“Register” 填写注册信息，这里的邮箱最好使用自己的邮箱，不要使用临时邮箱，以防万一后面作者发送邮件进行验证之类的 信息填写完成后滑倒最下面，勾选I have read and accept the terms of service and privacy policy.，然后点击“Validate” 成功后会转到邮箱验证界面 打开邮箱，复制token 返回验证界面，填写用户名和token，然后点击“Validate” 完成后跳转到登录界面，这时候就可以使用刚刚注册的时候填写的用户名和密码登录了 填写用户名和密码，点击“Validate”登录 第二步：申请一个不需要的域名 我们做这个步骤的原因是我们要获取自己CF的NS，每个账号的SN和不同时间解析的NS都是不一样的，所以我们需要先申请一个自己不需要的域名按照正常流程托管到CF获取自己的NS 登录成功后，可以看到有两个域名可以选择，我们选择第一个“.netlib.re”，这个是可以托管到CF的，而另一个不行 然后随便输入一个三级域前缀，然后点击“add a new domain” 成功后就可以看到我们申请的域名了 第三步：获取CF的NS 打开登录CF，我们按照正常流程托管域名，点击左上角的“加入域” 填写刚刚申请到的域名，然后点击“继续” 选择免费的计划 复制这两个NS保存备用，到这里我们就获取到CF的NS了 第四步：正式申请域名以及修改NS 现在就可以正式申请和托管域名了 输入我们想要的三级域名前缀，然后点击“add a new domain” 之后马上点击我们刚刚添加的域名 跳转到域名设置界面后马上下滑，找到“Delegation”下的“Delegate your domain to different name servers”并点击 然后把刚刚我们获取到的NS填入进去，填入完成后点击“Delegate the domain”保存 看到下面这个界面的时候就是成功了 第五步：托管域名 打开CF，按照正常流程添加域名 点击“加入域” 输入我们刚刚正式申请的域名，然后点击“继续” 选择免费计划 到下面这个界面，只要C没有提示删除其他名称服务器就成功了，耐心等待几分钟 第六步：确定托管是否可用 返回到主页，点击我们刚刚托管的域名 点击左边导航栏的“SSL/TLS” 点击“边缘证书” 看到边缘证书状态为“有效”就是成功了 声明 次方法不确定什么时候失效，目前还是可以正常托管的，不知道后面会不会像cloudns一样托管不上去了
简介 Ventoy是一个制作可启动U盘的开源工具。 有了Ventoy你就无需反复地格式化U盘，你只需要把 ISO/WIM/IMG/VHD(x)/EFI 等类型的文件直接拷贝到U盘里面就可以启动了，无需其他操作。 你可以一次性拷贝很多个不同类型的镜像文件，Ventoy 会在启动时显示一个菜单来供你进行选择 你还可以在 Ventoy 的界面中直接浏览并启动本地硬盘中的 ISO/WIM/IMG/VHD(x)/EFI 等类型的文件。 Ventoy 安装之后，同一个U盘可以同时支持 x86 Legacy BIOS、IA32 UEFI、x86_64 UEFI、ARM64 UEFI 和 MIPS64EL UEFI 模式，同时还不影响U盘的日常使用。 Ventoy 支持大部分常见类型的操作系统 （Windows/WinPE/Linux/ChromeOS/Unix/VMware/Xen ...） （上面简介复制Ventoy官方的） 既然都出这个教程了，那就从零开始吧，从如何制作启动盘开始吧 准备工具 一个U盘 一台电脑 下载Ventoy 打开Ventoy官网 https://www.ventoy.net/cn/index.html 点击顶部导航栏的【下载】 选择对应自己系统的版本，我选择的windows 点击后会跳转到github上 继续点击对应的系统版本下载 等待下载完成后解压 制作启动盘 把U盘插入电脑，记得备份你的资料，U盘要格式化的 然后打开刚刚解压的文件夹 双击运行“Ventoy2Disk.exe” 选择好U盘，然后点击【安装】 弹出是否格式化，点击【是】 完成后点击【确定】 修改主题 下载主题 我们并不需要自己去做主题，我们直接拿别人做好的来使用即可，当然如果想自己做也是可以的，但是这篇文章不会教如何自己做，后续可能会单独开一篇文章来说 首先我们去寻找自己喜欢的主题，寻找的渠道有两个，一个是github，另外一个是下面这个网站 https://www.gnome-look.org/browse/ 打开后我们点击右边的“GRUB Themes” 点击顶部的“Rating”，按评分排序 找到自己喜欢的，点击进去 点击右上角的【Download】下载 点击【Download】后如果有多个文件会弹出一个列表，让你选择下载哪一个，如果不清楚可以进入下面的github地址看一下说明 例如这个，进入github后就可以看到那个名字的主题是什么样的 等待几秒，然后点击【Download】 下载完成后解压出来 设置主题 进入我们第一个下载解压出来的Ventoy文件夹 双击运行“VentoyPlugson.exe”，选择好U盘，然后点击【启动】 这时候会打开浏览器，进入设置界面 导入主题 点击左边的“主题插件” 找到“file —— 主题配置文件”，点击右边的【新增】 这时候会叫我们输入文件路径 我们打开刚刚解压的主题文件夹 打开里面的“darkmatter”文件夹 找到“theme.txt”这个文件 复制文件路径，并填写到浏览器中刚刚我们点击【新增】弹出来的窗口中，然后点击【确定】 这里有一个坑，那就是解压出来的主题压缩包一定要放到Ventoy的U盘里面，否则会路径不对 提示配置文件保存成功，文件存在就可以了 到这里就结束了，可以关闭所有窗口了，可以重启看看是否成功了
简介 之前使用的云服务器都是阿里云的，主要是阿里云便宜，但是最近不知道什么问题，使用阿里云的服务器延迟总是很高，然后丢包率也高，所以换了腾讯云 虽然说腾讯云比阿里云贵了那么亿点，但是真TM稳啊，应该是线路优化了 每家的云服务器都会有监控进程，这些进程不能说没有用，还是有那么一点用处的，但是占用资源高啊 如果在系统进程中看到YDService、tat_agent、YDLive、sgagent、barad_agent这些都是云镜、云监控相关软件的进程 卸载云镜等命令 systemctl stop tat_agent systemctl disable tat_agent /usr/local/qcloud/YunJing/uninst.sh /usr/local/qcloud/stargate/admin/uninstall.sh /usr/local/qcloud/monitor/barad/admin/uninstall.sh 删除云监控相关目录文件 rm -f /etc/systemd/system/tat_agent.service rm -rf /usr/local/qcloud 最后清理 打开/etc/rc.local 文件，将里面含qcloud的行全部删掉。 vi /etc/rc.local 找到包含qcloud的，全部删掉 然后重启服务器
简介 Vikunja是一款功能强大的开源任务管理工具，它帮助用户以一种有组织的方式管理和跟踪所有待办事项。 就像一个拥有超能力的笔记本，Vikunja允许个人或团队轻松地规划、协作并完成项目。 无论是个人使用还是团队合作，Vikunja都提供了灵活性和定制性，让用户能够根据自己的需求调整任务管理方式 环境与安装方式 Vikunja支持二进制安装，docker安装，从源码自己构建安装，我这里使用的是二进制安装 我安装的环境是X86架构的linux（Almalinux） 项目官网/下载地址 和其他的开源程序不一样，这个再Github里面也可以找到，但是里面只有源码，没有编译好的二进制文件等，需要二进制文件的话可以到它的官网下载。 项目官网：https://vikunja.io/ github项目地址：https://github.com/go-vikunja/vikunja 官方下载仓库地址：https://dl.vikunja.io/vikunja/ 下载/解压Vikunja 进入官方的下载仓库地址 点击最新版的版本号，这里注意，有的版本号带rc的，带rc的是候选版本，可以理解为测试版本，我们需要的是稳定版的 找到适合自己服务器软硬件的版本，鼠标右键，复制链接地址 使用ssh工具连接到服务器，然后根据自己的习惯创建一个文件夹，用于存放软件，我的习惯是自己安装的软件放在/opt/下面对应的文件夹里面 cd /opt mkdir vikunja 进入刚刚创建的文件夹 cd vikunja 使用wget命令下载刚刚复制的链接 wget 刚刚再下载仓库复制的链接 wget https://dl.vikunja.io/vikunja/0.24.6/vikunja-v0.24.6-linux-amd64-full.zip 下载完成后可以使用ls命令查看下载的文件 下载下来的是一个zip包，使用unzip解压，解压完成后可以使用ls命令查看解压出来的文件 unzip vikunja-v0.24.6-linux-amd64-full.zip 为了方便管理，我们需要删除不需要的文件 rm LICENSE vikunja-v0.24.6-linux-amd64-full.zip vikunja-v0.24.6-linux-amd64.sha256 然后把二进制文件重命名一下，方便后续升级更新 mv vikunja-v0.24.6-linux-amd64 vikunja 配置Vikunja 刚刚解压出来的文件里面有一个config.yml.sample，这个是官方的配置示例文件，我们可以在这个文件上进行修改或者参考这个文件写一个新的config.yml文件 下面是翻译后的配置文件示例 service: # 此令牌用于验证签发的 JWT 令牌。 # 默认是随机生成的，每次启动 Vikunja 都会生成新的。 # （这意味着重启 Vikunja 后所有已签发的令牌都会失效） JWTSecret: "<jwt-secret>" # JWT 令牌有效期（秒），默认 259200 秒（3 天） jwtttl: 259200 # “记住我”模式令牌有效期（秒），默认 2592000 秒（30 天） jwtttllong: 2592000 # Web 服务器运行接口 interface: ":3456" # Unix 套接字路径，如果设置，将使用套接字而不是 TCP unixsocket: # Unix 套接字权限，八进制值需以 0o 前缀，例如 0o660 unixsocketmode: # 用户访问 Vikunja 的公共 URL，用于邮件和前后端通信 publicurl: "" # 可执行文件和资源所在的根路径 # Vikunja 也会在此路径查找配置文件 rootpath: <rootpath> # 每页最大返回项目数 maxitemsperpage: 50 # 是否启用 CalDAV 接口 enablecaldav: true # 设置每日消息（MOTD），通过 /info 接口可见 motd: "" # 是否允许通过链接共享项目 enablelinksharing: true # 是否允许新用户自行注册 enableregistration: true # 是否允许任务附件 enabletaskattachments: true # 所有时间戳使用的时区，需使用官方 tz 数据库名称（UTC/GMT 不可用） timezone: GMT # 是否启用任务评论 enabletaskcomments: true # 是否启用 TOTP 双因素认证 enabletotp: true # 如果不为空，将启用 /test/{table} 接口用于测试，可写入任意内容 # 非常危险，除非明确知道用途，否则不要启用 testingtoken: '' # 是否在任务到期时发送邮件提醒 enableemailreminders: true # 是否允许用户请求删除账号 enableuserdeletion: true # 用户头像最大尺寸（KB） maxavatarsize: 1024 # 是否显示演示模式警告（数据会被清空） demomode: false # 是否允许根据节日更换图标 allowiconchanges: true # 是否允许使用自定义 Logo customlogourl: '' # 是否启用公开团队功能，使团队可被发现 enablepublicteams: false sentry: # 是否启用 API 错误匿名跟踪（Sentry） enabled: false # 配置 Sentry DSN 用于 API 错误跟踪 dsn: "https://440eedc957d545a795c17bbaf477497c@o1047380.ingest.sentry.io/4504254983634944" # 是否启用前端错误匿名跟踪 frontendenabled: false # 配置 Sentry DSN 用于前端错误跟踪 frontenddsn: "https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480" database: # 数据库类型，可选 sqlite、mysql、postgres type: "sqlite" # 数据库用户名 user: "vikunja" # 数据库密码 password: "" # 数据库主机 host: "localhost" # 数据库名称 database: "vikunja" # 使用 sqlite 时数据库文件路径 path: "./vikunja.db" # 数据库最大打开连接数（仅 mysql/postgres） maxopenconnections: 100 # 数据库最大空闲连接数（仅 mysql/postgres） maxidleconnections: 50 # 单个数据库连接最大存活时间（毫秒） maxconnectionlifetime: 10000 # postgres 安全连接模式，可选 disable/require 等 sslmode: disable # postgres 客户端证书路径 sslcert: "" # postgres 客户端密钥路径 sslkey: "" # postgres 根证书路径 sslrootcert: "" # mysql 启用 SSL/TLS，可选 false/true/skip-verify/preferred tls: false typesense: # 是否启用 Typesense 集成，启用后所有任务通过 Typesense 搜索 enabled: false # Typesense 实例 URL url: '' # Typesense API key apikey: '' redis: # 是否启用 Redis enabled: false # Redis 服务器地址和端口 host: 'localhost:6379' # Redis 密码 password: '' # 使用的数据库编号（0 为默认） db: 0 cors: # 是否启用 CORS 头 enable: false # 允许访问 API 的来源列表（需包含协议 http:// 或 https://） origins: - "*" # 预检请求结果缓存时间（秒） maxage: 0 mailer: # 是否启用邮件功能，禁用后用户注册立即生效且无法重置密码 enabled: false # SMTP 主机 host: "" # SMTP 端口（若遇 EOF 错误可尝试改为 25） port: 587 # SMTP 验证类型，可选 plain、login、cram-md5 authtype: "plain" # SMTP 用户名 username: "user" # SMTP 密码 password: "" # 是否跳过 TLS 验证 skiptlsverify: false # 默认发件人邮箱 fromemail: "mail@vikunja" # 邮件队列长度 queuelength: 100 # 邮件连接超时时间（秒） queuetimeout: 30 # 是否强制使用 SSL forcessl: false log: # 日志文件保存目录 path: <rootpath>logs # 是否启用日志 enabled: true # 普通日志输出方式，可选 stdout/stderr/file/off standard: "stdout" # 日志级别，可选 CRITICAL/ERROR/WARNING/NOTICE/INFO/DEBUG level: "INFO" # 是否记录数据库查询（调试用），可选 stdout/stderr/file/off database: "off" databaselevel: "WARNING" # 是否记录 HTTP 请求 http: "stdout" # Echo 日志，通常不需要 echo: "off" # 是否记录事件日志 events: "off" eventslevel: "info" # 是否记录邮件相关日志 mail: "off" maillevel: "info" ratelimit: # 是否启用速率限制 enabled: false # 速率限制类型，可选 user 或 ip kind: user # 限制周期（秒） period: 60 # 单位周期最大请求数 limit: 100 # 计数存储方式，可选 keyvalue/memory/redis store: keyvalue # 未认证用户每分钟访问限制（登录、注册、密码重置等接口） noauthlimit: 10 files: # 文件存储路径 basepath: ./files # 相对于二进制文件 # 文件最大体积 maxsize: 20MB migration: todoist: # 是否启用 Todoist 导入 enable: false # Todoist API client id clientid: # Todoist API client secret clientsecret: # 授权后回调 URL redirecturl: <service.publicurl>/migrate/todoist trello: # 是否启用 Trello 导入 enable: false key: redirecturl: <frontend url>/migrate/trello microsofttodo: # 是否启用 Microsoft ToDo 导入 enable: false clientid: clientsecret: redirecturl: <frontend url>/migrate/microsoft-todo avatar: # 使用 Gravatar 时缓存过期时间（秒） gravatarexpiration: 3600 backgrounds: # 是否启用项目背景 enabled: true providers: upload: # 是否允许上传背景 enabled: true unsplash: # 是否允许 Unsplash 背景 enabled: false accesstoken: applicationid: legal: # 法律相关 URL，会显示在前端 imprinturl: privacyurl: keyvalue: # 键值存储类型，可选 memory 或 redis type: "memory" auth: # 本地认证设置 local: enabled: true # OpenID 第三方认证 openid: enabled: false providers: - name: authurl: logouturl: clientid: clientsecret: scope: openid email profile metrics: # 是否启用 Prometheus /metrics 端点 enabled: false username: password: defaultsettings: # 新用户默认设置 avatar_provider: initials avatar_file_id: 0 email_reminders_enabled: false discoverable_by_name: false discoverable_by_email: false overdue_tasks_reminders_enabled: true overdue_tasks_reminders_time: 9:00 default_project_id: 0 week_start: 0 language: <unset> timezone: webhooks: # 是否启用 Webhooks enabled: true timeoutseconds: 30 proxyurl: proxypassword: 配置文件修改位置 我的配置文件主要修改了以下几个地方： 1、service模块 JWTSecret 设置为固定的 publicurl 设置为域名 rootpath 改为二进制文件的绝对路径 timezone 改为 GMT 2、mailer模块 SMTP 邮箱配置改为你的 QQ 邮箱 password 改为邮箱授权码 3、log模块 日志路径改为 /opt/vikunja/log/ 4、defaultsettings模块 language 改为 zh-CN timezone 改为 Asia/Shanghai 下面是我修改后的配置文件 service: # 此令牌用于验证签发的 JWT 令牌。 # 默认是随机生成的，每次启动 Vikunja 都会生成新的。 # （这意味着重启 Vikunja 后所有已签发的令牌都会失效） JWTSecret: "12345678" # JWT 令牌有效期（秒），默认 259200 秒（3 天） jwtttl: 259200 # “记住我”模式令牌有效期（秒），默认 2592000 秒（30 天） jwtttllong: 2592000 # Web 服务器运行接口 interface: ":3456" # Unix 套接字路径，如果设置，将使用套接字而不是 TCP unixsocket: # Unix 套接字权限，八进制值需以 0o 前缀，例如 0o660 unixsocketmode: # 用户访问 Vikunja 的公共 URL，用于邮件和前后端通信 publicurl: "https://task.ersansi.top" # 可执行文件和资源所在的根路径 # Vikunja 也会在此路径查找配置文件 rootpath: /opt/vikunja/ # 每页最大返回项目数 maxitemsperpage: 50 # 是否启用 CalDAV 接口 enablecaldav: true # 设置每日消息（MOTD），通过 /info 接口可见 motd: "" # 是否允许通过链接共享项目 enablelinksharing: true # 是否允许新用户自行注册 enableregistration: true # 是否允许任务附件 enabletaskattachments: true # 所有时间戳使用的时区，需使用官方 tz 数据库名称（UTC/GMT 不可用） timezone: GMT # 是否启用任务评论 enabletaskcomments: true # 是否启用 TOTP 双因素认证 enabletotp: true # 如果不为空，将启用 /test/{table} 接口用于测试，可写入任意内容 # 非常危险，除非明确知道用途，否则不要启用 testingtoken: '' # 是否在任务到期时发送邮件提醒 enableemailreminders: true # 是否允许用户请求删除账号 enableuserdeletion: true # 用户头像最大尺寸（KB） maxavatarsize: 1024 # 是否显示演示模式警告（数据会被清空） demomode: false # 是否允许根据节日更换图标 allowiconchanges: true # 是否允许使用自定义 Logo customlogourl: '' # 是否启用公开团队功能，使团队可被发现 enablepublicteams: false sentry: # 是否启用 API 错误匿名跟踪（Sentry） enabled: false # 配置 Sentry DSN 用于 API 错误跟踪 dsn: "https://440eedc957d545a795c17bbaf477497c@o1047380.ingest.sentry.io/4504254983634944" # 是否启用前端错误匿名跟踪 frontendenabled: false # 配置 Sentry DSN 用于前端错误跟踪 frontenddsn: "https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480" database: # 数据库类型，可选 sqlite、mysql、postgres type: "sqlite" # 数据库用户名 user: "vikunja" # 数据库密码 password: "" # 数据库主机 host: "localhost" # 数据库名称 database: "vikunja" # 使用 sqlite 时数据库文件路径 path: "./vikunja.db" # 数据库最大打开连接数（仅 mysql/postgres） maxopenconnections: 100 # 数据库最大空闲连接数（仅 mysql/postgres） maxidleconnections: 50 # 单个数据库连接最大存活时间（毫秒） maxconnectionlifetime: 10000 # postgres 安全连接模式，可选 disable/require 等 sslmode: disable # postgres 客户端证书路径 sslcert: "" # postgres 客户端密钥路径 sslkey: "" # postgres 根证书路径 sslrootcert: "" # mysql 启用 SSL/TLS，可选 false/true/skip-verify/preferred tls: false typesense: # 是否启用 Typesense 集成，启用后所有任务通过 Typesense 搜索 enabled: false # Typesense 实例 URL url: '' # Typesense API key apikey: '' redis: # 是否启用 Redis enabled: false # Redis 服务器地址和端口 host: 'localhost:6379' # Redis 密码 password: '' # 使用的数据库编号（0 为默认） db: 0 cors: # 是否启用 CORS 头 enable: false # 允许访问 API 的来源列表（需包含协议 http:// 或 https://） origins: - "*" # 预检请求结果缓存时间（秒） maxage: 0 mailer: # 是否启用邮件功能，禁用后用户注册立即生效且无法重置密码 enabled: true # SMTP 主机 host: "smtp.qq.com" # SMTP 端口（若遇 EOF 错误可尝试改为 25） port: 465 # SMTP 验证类型，可选 plain、login、cram-md5 authtype: "plain" # SMTP 用户名 username: "11111111@qq.com" # SMTP 密码 password: "11111111" # 是否跳过 TLS 验证 skiptlsverify: false # 默认发件人邮箱 fromemail: "11111111@qq.com" # 邮件队列长度 queuelength: 100 # 邮件连接超时时间（秒） queuetimeout: 30 # 是否强制使用 SSL forcessl: true log: # 日志文件保存目录 path: /opt/vikunja/log/ # 是否启用日志 enabled: true # 普通日志输出方式，可选 stdout/stderr/file/off standard: "stdout" # 日志级别，可选 CRITICAL/ERROR/WARNING/NOTICE/INFO/DEBUG level: "INFO" # 是否记录数据库查询（调试用），可选 stdout/stderr/file/off database: "off" databaselevel: "WARNING" # 是否记录 HTTP 请求 http: "stdout" # Echo 日志，通常不需要 echo: "off" # 是否记录事件日志 events: "off" eventslevel: "info" # 是否记录邮件相关日志 mail: "off" maillevel: "info" ratelimit: # 是否启用速率限制 enabled: false # 速率限制类型，可选 user 或 ip kind: user # 限制周期（秒） period: 60 # 单位周期最大请求数 limit: 100 # 计数存储方式，可选 keyvalue/memory/redis store: keyvalue # 未认证用户每分钟访问限制（登录、注册、密码重置等接口） noauthlimit: 10 files: # 文件存储路径 basepath: ./files # 相对于二进制文件 # 文件最大体积 maxsize: 20MB migration: todoist: # 是否启用 Todoist 导入 enable: false # Todoist API client id clientid: # Todoist API client secret clientsecret: # 授权后回调 URL redirecturl: <service.publicurl>/migrate/todoist trello: # 是否启用 Trello 导入 enable: false key: redirecturl: <frontend url>/migrate/trello microsofttodo: # 是否启用 Microsoft ToDo 导入 enable: false clientid: clientsecret: redirecturl: <frontend url>/migrate/microsoft-todo avatar: # 使用 Gravatar 时缓存过期时间（秒） gravatarexpiration: 3600 backgrounds: # 是否启用项目背景 enabled: true providers: upload: # 是否允许上传背景 enabled: true unsplash: # 是否允许 Unsplash 背景 enabled: false accesstoken: applicationid: legal: # 法律相关 URL，会显示在前端 imprinturl: privacyurl: keyvalue: # 键值存储类型，可选 memory 或 redis type: "memory" auth: # 本地认证设置 local: enabled: true # OpenID 第三方认证 openid: enabled: false providers: - name: authurl: logouturl: clientid: clientsecret: scope: openid email profile metrics: # 是否启用 Prometheus /metrics 端点 enabled: false username: password: defaultsettings: # 新用户默认设置 avatar_provider: initials avatar_file_id: 0 email_reminders_enabled: false discoverable_by_name: false discoverable_by_email: false overdue_tasks_reminders_enabled: true overdue_tasks_reminders_time: 9:00 default_project_id: 0 week_start: 0 language: zh-CN timezone: Asia/Shanghai webhooks: # 是否启用 Webhooks enabled: true timeoutseconds: 30 proxyurl: proxypassword: 保存并退出 ：wq 查看配置文件名称是否正确，配置文件名称为config.yml 测试启动 确定配置文件名称没问题后，测试一下是否可以正常启动，启动后没报错就是成功了 ./vikunja 这时候我们使用浏览器访问服务器地址加端口号就可以看到登录页面了 配置开机自启 只要看到登录页面就是正常了，接下来就是配置开机自启了 首先按【Ctrl】+【c】停止 然后进入服务文件目录 cd /etc/systemd/system 创建一个.service文件 vi vikunja.service 把下面内容根据自己实际情况修改，然后粘贴进去，注意把注释全部删掉 [Unit] Description=Vikunja After=syslog.target network.target Requires=postgresql.service # 根据实际数据库选择 #Requires=mysql.service #Requires=redis.service [Service] Type=simple WorkingDirectory=/opt/vikunja # 二进制文件所在目录路径 ExecStart=/opt/vikunja/vikunja #二进制文件路径 Restart=always RestartSec=2s [Install] WantedBy=multi-user.target 保存并退出 修改文件权限 chmod +x vikunja.service 刷新system文件 sudo systemctl daemon-reload 启动vikunja systemctl start vikunja.service 设置开机自启 systemctl enable vikunja.service 使用 第一次登录 vikunja是没有默认管理员账号密码的，第一次登录是需要先注册一个账号密码 而且vikunja是没有管理员的，所有用户注册后就是普通用户，想要修改配置等都需要手动修改config文件 创建待办任务 点击【项目】 点击【新建项目】 输入标题，然后点击【创建】 这样一个大项目就创建好了，可以在这个大项目下面创建小项目 点击大项目旁边的三个点，然后点击【创建项目】 输入项目标题，然后点击【创建】 这样就创建好小项目了 接下来创建任务 点击项目名称，然后输入任务名称，点击【添加】 任务创建好后需要设置任务，点击任务右边的两条杠 在里面设置任务内容，时间等 更新 首先进行备份，备份当前版本的二进制文件 只需将二进制文件替换为新版本，然后重新启动 Vikunja。它将自动运行所有必要的数据库迁移。 请务必查看新版本的更新日志，以免错过更新过程中可能涉及的任何手动步骤！