网站一直以来都是使用的Let's Encrypt SSL证书，主要是因为Let's Encrypt浏览器兼容性较好，支持ACME自动化部署，支持泛域名证书等，但是今天起网站开始放弃Let's Encrypt证书，全站更换ZeroSSL提供的SSL证书。为什么放弃Let's Encrypt证书？由于Let's Encrypt证书的OCSP验证域名由于未知原因无法访问，不过网站前一阵子给服务器开启了OCSP装订，变相解决了部分浏览器访问缓慢的问题；但是经过测试，发现有些浏览器，比如IOS端 Chromium 系的浏览器：Chrome、新版Egde等，就算服务器开启了OCSP装订，还是会去强制访问OCSP验证证书有效性，虽然超时时间只有3s，但是问题没有得到解决就很不爽； 不过也没有更好的解决办法了。并且Let's Encrypt的X3根证书也将到期，之后会使用自己签发的根证书，虽然根证书更换后OCSP无法访问的问题会得到解决，但是新的根证书时间太短导致安卓7以下以及16年以前的一些设备没办法信任这个证书导致老设备的兼容性问题；看来只能更换SSL证书来彻底解决该问题了。 为什么选择ZeroSSL？经过大佬Luminous推荐，ZeroSSL家的SSL证书可支持ACME自动化部署，并且支持申请泛域名证书，所以准备考虑切换到这家CA的证书；ZeroSSL的证书之前也听说过，没有考虑的原因是之前我点开价格后发现免费用户只能签3个单域名证书，其他的类型证书都是收费的（贫穷限制了我的想象力）；不过也怪我研究不够深入，在ACME文档的介绍中发现，通过ACME自动部署的方式，可以进行无限制的签发普通域名、多域名证书、甚至通配证书等，并且可以acme.sh脚本官方也支持直接将CA切换到ZeroSSL，直接一键就可以完成证书的切换！ 既然更换证书的成本这么低了，那何乐而不为呢？ 接下来就准备直接将acme.sh的证书由默认的Let's Encrypt CA切换到ZeroSSL CA；更换ACME.sh的CA为ZeroSSL这里我的证书是使用acme.sh统一管理的，并且acme.sh官方也支持切换CA到ZeroSSL；acme.sh 的安装可参考官方文档：https://github.com/acmesh-official/acme.sh/wiki/How-to-install下文主要是通过DNS的方式进行证书的签发，该方式在签发证书的时候会自动在dns解析中添加验证域名需要的解析，并且在验证完毕后会自动删除解析；acme.sh 目前支持 cloudflare, dnspod, godaddy 以及 ovh 等数十种解析商的自动集成配置很简单，只需将自己dns服务商提供的dnsapi配置到环境变量中即可由于之前在使用Let's Encrypt的时候已经配置过，在此就不进行过多阐述dnsapi 具体配置可参考官方文档：传送门：https://github.com/acmesh-official/acme.sh/wiki/dnsapi下面将acme.sh申请的证书由默认的Let's Encrypt更改为ZeroSSL1.访问账户注册页面注册一个ZeroSSL账户传送门：https://app.zerossl.com/signup2.获取账户的EAB凭证，用来注册acme帐户传送门：https://app.zerossl.com/developer点击生成会生成你的eab-kid和eab-hmac-key，复制保存下来；3.注册ACME帐户acme.sh --register-account --server zerossl \ --eab-kid 你的eab-kid \ --eab-hmac-key 你的eab-hmac-key4.切换默认CA接下来你就可以添加--server zerossl指令来签发新的证书了，如下：acme.sh --server zerossl --issue --dns dns_dp -d ffis.me -d *.ffis.me或者直接切换acme.sh的默认CA为ZeroSSLacme.sh --set-default-ca --server zerossl5.签发新证书，这里我签发的是泛域名证书acme.sh --issue --dns dns_dp -d ffis.me -d *.ffis.me签发完毕后证书会保存在/root/.acme.sh目录下，我们一般不直接访问此目录6.安装新证书acme.sh --install-cert -d ffis.me \ --key-file /usr/local/nginx/conf/ssl/ffis.me.key \ --fullchain-file /usr/local/nginx/conf/ssl/ffis.me.crt \ --reloadcmd "systemctl force-reload nginx.service"以上命令会将证书复制到nginx指定目录下，并且强制重新加载nginx，并且以后每次自动续期都会自动执行以上逻辑；安装完毕后，我们修改网站nginx配置文件中ssl证书文件地址为上面的安装地址即可。经过如上操作，我的SSL证书就更换为ZeroSSL家的证书了！这样OCSP无法访问的问题也就迎刃而解了，当然也可以自己去配置OCSP装订和手动预缓存，来提高加载速度
1 前言作为一个计算机爱好者，选择统一的密码还是每个软件一个单独的密码，永远是个困境；一个人要记住太多的密码是不太现实的，保持密码以书面形式又是非常不安全的；对于数量越来越多的账号密码，一直以来，我都在寻找一个安全、快速、方便的密码长期保存方式；从手写笔记到手机备忘录，从txt文档到word文档，从自己手动备份到onedrive自动同步... 现如今比较流行的方式是使用密码管理工具进行密码的统一管理，这类软件一般拥有多平台客户端、浏览器插件等，密码一般加密保存到本地或者云端；密码管理工具很多，有人说最好的密码管理工具是 1Password，但是他实在是卖的太贵了，暂时不考虑；再对比各大软件，其实各有特色。有的倾向于将密码库储存到云端，有的可将密码库储存到本地进行自己保存，有的开源，有的是私有化，有的还提供私有化部署 最终我选择使用Bitwarden来搭建私人密码库，比较全的客户端覆盖，提供开源免费版，还提供私有化部署，满足了我对密码库的所有要求；2 Bitwarden ServerBitwarden 官方提供私有化部署，有一键部署脚本和手动部署两种方式，不过官方由于使用的是 MSSQL 数据库，整体部署下来对机器配置要求较高官方推荐服务器配置只部署一个私人密码库，使用这么重量级的应用是不符合我的习惯的（钱包顶不住） 经过我的一番查找，终于在Github发现了有dalao使用 Ruby 开发了一个兼容的 Bitwarden 服务器：bitwarden_rs，并且提供了 Docker 镜像部署；Github传送门：https://github.com/dani-garcia/bitwarden_rs该服务器端系统配置要求很低，Docker镜像体积也很小，部署非常方便，使用 SQLite 服务器来存储数据，对于个人来说已经足够；最终就选择使用它来作为我的密码库的服务器端。3 准备首先需要你有一个域名，一台安装了Docker环境的服务器；可参考Docker官方文档：https://docs.docker.com/get-docker/ 来进行Docker的安装为方便部署和更新，本文使用 docker-compose 来管理服务在linux下可使用如下命令进行 docker-compose 的安装和更新sudo curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose如果要进行更新，替换1.27.4为最新的版本号即可。查看最新版本：https://github.com/docker/compose/releases4 安装Bitwarden4.1 创建Bitwarden数据存放目录mkdir -p /data/bitwarden && cd /data/bitwarden4.2 创建docker-compose配置文件cat >> docker-compose.yml <<EOF version: '3' services: # 服务名称 bitwarden: # 指定使用 Docker Hub 中的最新镜像 image: bitwardenrs/server:latest # 容器名称 container_name: bitwarden # 开机自动启动 restart: always # 指定容器内的 /data 目录挂载到宿主机的当前目录下的 /data/bitwarden/data 目录，这样你可以在宿主机上执行数据库的备份操作 volumes: - /data/docker/bitwarden/data:/data # bitwarden配置 environment: # 开启网页访问 WEB_VAULT_ENABLED: 'true' # 开启新用户注册，我们注册后关闭即可 SIGNUPS_ALLOWED: 'true' # 开启长连接 WEBSOCKET_ENABLED: 'true' # 日志文件 LOG_FILE: /data/bitwarden.log # 将容器内的80/3012端口映射到宿主机的7006/7007端口；其中80端口为 HTTP 服务，3012 端口是 websockets 服务 ports: - 7006:80 - 7007:3012 EOF4.3 Nginx反向代理配置#bitwarden location / { proxy_pass http://127.0.0.1:7006; 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 /notifications/hub { proxy_pass http://127.0.0.1:7007; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /notifications/hub/negotiate { proxy_pass http://127.0.0.1:7006; }以上配置为最基础的配置，你还可以加入 HSTS / 压缩 / XSS 防护等配置；详细配置请参考官方文档：https://github.com/dani-garcia/bitwarden_rs/wiki/Proxy-examples现在已经是 2020 年，请为域名配置 HTTPS 证书，并将 HTTP 流量阻挡或重定向到 HTTPS，以保障数据传输的安全。4.4 启动docker服务docker-compose up -d4.5 内存占用可以看到，该服务器端仅仅占用10M内存5 用户注册和数据导入启动完成后，我们就可以通过我们配置的域名来访问网页版了点击创建账号进行账号的注册注册登录后可在上方的工具中进行数据导入，支持多种格式的数据导入6 关闭新用户注册现在你的bitwarden服务器允许任何人访问和注册，如果你只需要自己使用，可以关闭用户注册功能。调整docker-compose配置文件SIGNUPS_ALLOWED: 'false'改动配置后需要运行以下命令来删除并重新创建容器以使配置生效，无需担心你的数据，我们的数据均保存在我们第4.1中创建的目录中docker-compose down && docker-compose up -d这样就关闭了用户注册功能，并禁用了 web 的访问。密码数据我们还是可以在客户端中进行编辑的。7 登录客户端服务器端安装完毕后，我们需要登录到客户端来进行密码的管理和自动填充，Bitwarden的客户端都大同小异，这里以Chrome扩展为例：首先我们在登录页面点击小齿轮然后我们填入我们自己的Bitwarden服务器地址之后使用我们刚刚注册的账号进行登录即可，其他客户端的配置和这里是一样的。8 备份我们在使用过程中的所有数据都保存在我们创建的目录：/data/bitwarden 中为保证数据安全我们最好定期将该目录的数据进行备份你可以自己手动备份也可以使用我们的自动备份脚本：WebServerAutoBackupGithub: https://github.com/ehaut/WebServerAutoBackup配置文件中填写备份目录为：/data/bitwarden然后在crontab定时任务中添加定时任务，即可每日进行备份到你指定的地方。#每日凌晨 2:15 备份bitwarden 15 2 * * * cd /root/WebServerAutoBackup && ./backup.sh config-bitwarden.ini > /data/backup/log/bitwarden-cron.log 2>&1 & 19 更新由于使用的是非官方的服务器端，所以作者们会经常同步更新到官方的更新中，以保证与客户端的兼容性更新也是直接运行如下命令即可cd /data/bitwarden //停止运行的bitwarden容器 docker-compose stop //拉取最新镜像 docker-compose pull //重新构建并启动 docker-compose up -d --build10 安全提醒对于使用任何密码管理工具的人来说，主密码的重要性不言而喻。一旦主密码泄漏，相当于将所有帐号密码拱手相让；一旦主密码丢失，所有数据也都化作随机噪音，变得一文不值。所以，请时常审视、改进你的安全策略，定期对帐号做安全审查，不定期修改并牢记主密码。Thanks：本文无耻的 参考了 基本抄袭了JokerQyou的文章：https://blog.mynook.info/post/selfhost-bitwarden/
1 起因最近突然发现我的网站在苹果手机上Safari浏览器上第一次会访问会非常慢，但只要第一次访问后，后续的访问速度均不受影响...这就纳闷了，网站速度我都是优化过的，为什么会存在这种情况呢？困扰我许久，因为只有手机访问才这样，在电脑上访问速度都很快，完全没有头绪... 2 问题研究在多次尝试后，发现在Firefox和IE浏览器上能复现该问题，在ssl握手之前，Firefox会阻塞2s，IE浏览器会阻塞10s以上；问题能复现就好解决了；使用Charles进行抓包，发现使用IE打开网站的时候，会去请求ocsp.int-x3.letsencrypt.org域名进行证书验证，该域名无法访问从而导致访问速度变慢；所以问题就出在SSL证书上面，我使用的证书全部是Let's Encrypt证书，其特点是免费、支持泛域名、并且脚本一键部署，但是Let's Encrypt证书的OCSP验证域名被DNS污染，无法解析到正确的IP地址，导致无法进行证书有效性验证。这时候有同学要问了：OCSP验证又是什么呢？OCSP 称 Online Certificate Status Protocol，即在线证书状态协议。说白了就是查询你的SSL证书是不是被提供商吊销了，正常访问一个网站时，浏览器要先去使用OCSP协议去查询你的证书是否有效，如果有效才进行接下来的操作；可全球这么多网站，都去验证的话OCSP服务器也扛不住，所以查询就可能超时；不同浏览器都会有不同的OCSP验证超时时间，超过那个时间就不进行验证了，先默认你是有效的继续进行访问。但是有些"注重用户体验"的浏览器，比如Chrome就感觉这种方式很不好，于是Chrome浏览器就不用这个协议了，自己在浏览器内部做了个本地列表，通过每次浏览器更新来进行列表更新；由于直接查本地的列表速度就非常快了，缺点是不是实时的；受Chromium项目的影响，国内的绝大部分换皮浏览器也使用的这个策略，所以大部分的浏览器压根就没有进行使用OCSP协议去验证SSL域名的有效性，所以大部分的浏览器访问速度就很快了；但是有些浏览器，比如苹果的Safari和IE就强制开启了OCSP验证，Firefox的OCSP验证可以在选项中关闭；由于Let's Encrypt证书的OCSP验证域名被DNS污染，无法进行验证，所以就出现了首次访问会很慢的原因，也就是OCSP验证超时了。如何解决DNS污染呢？其实也简单，不使用国内公共DNS就好了，使用国外公共DNS，例如8.8.8.8等，就可以正常访问Let's Encrypt的OCSP验证域名了；但是在国内使用8.8.8.8速度不是很理想，你也不可能要求所有人去使用这个DNS吧，所以还是得从源头解决这个问题。那么解决办法显而易见了~ 对！就是换个SSL证书！... 好了本文结束，感谢大家的阅读，完结撒花~~ 哈哈，换SSL证书说着简单，但是买一个泛域名证书属实挺贵的，钱包不允许个人也没必要买；市面上免费证书也只有腾讯阿里等大厂提供的单域名证书，申请麻烦还得一个个去部署更麻烦...对我来说不太现实所以还是得想办法解决DNS污染的问题，给每个人都换DNS服务器不现实，那直接给服务器换DNS服务器不就行了，OCSP验证放在网站服务器上并且缓存在本地，客户端直接查询服务器缓存的结果，也不用去等，多好 这时候就需要Nginx的OCSP装订功能了3 Nginx OCSP stapling由网站服务器去进行OCSP查询，缓存查询结果，然后在与浏览器进行TLS连接时返回给浏览器，这样浏览器就不需要再去查询了。是不是很棒？别急，开启之前我们是不是得先知道如何查询是否开启了OCSP装订，不然捣鼓半天都不知道开启成功了没有可还行..4 检测OCSP有两种方法：1.在线检测：亚洲诚信的SSL检测工具 https://myssl.com/2.手动检测：openssl s_client -connect ffis.me:443 -servername ffis.me -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"5 开启 OCSP stapling开启OCSP装订需要在网站的nginx配置文件中添加如下配置：# 开启 OCSP Stapling，开启后服务器在TLS握手时发送事先缓存的OCSP响应，用户只需验证该响应的有效性而不用再向数字证书认证机构（CA）发送请求 ssl_stapling on; # 启用或禁用服务器对OCSP响应的验证 ssl_stapling_verify on; # 证书的签发机构的ca证书，我的Let's Encrypt是acme.sh自动获取的证书，ca证书目录为：/root/.acme.sh/ffis.me/ca.cer ssl_trusted_certificate /usr/local/nginx/conf/ssl/ffis.me_ca.cer; # 添加resolver解析OSCP响应服务器的主机名，valid表示缓存。这里添加是为了解决DNS污染问题。 resolver 8.8.8.8 8.8.4.4 223.5.5.5 valid=60s; # 网络超时时间 resolver_timeout 2s;添加后，重启nginx服务器，再次使用命令验证，OCSP装订是不是就已经开启了？使用myssl验证，也提示OCSP已装订Firefox、IE、Safari浏览器的访问也正常了再次使用Charles进行抓包，发现浏览器会跳过OCSP验证6 弊端此方式实现了OCSP查询在服务器端进行，避免了浏览器去进行OCSP验证从而影响访问速度；但是OCSP响应的缓存并不是预加载的，而是异步加载的；在Nginx启动后，只有当有客户端访问的时候，Nginx才开始去请求OCSP响应并缓存到本地，并且当OCSP响应缓存过期的时候并不会去主动更新，而是等待客户端访问异步触发的更新；这样就会导致总会有几次访问并没有走OCSP响应缓存从而导致还是会有访问速度缓慢的情况发生。7 优化那如何解决呢？最好的办法就是我们人工去请求OCSP响应并保存到本地，Nginx直接加载保存好的响应信息就行了；这里我自己编写了Shell脚本去定时请求OCSP响应信息并保存到本地，利用 Nginx 的 ssl_stapling_file 指令直接读取本地响应信息，这样就不会去实时查询证书的OCSP服务器，在进行SSL握手的时候直接将本地的响应信息进行下发，极大的加快了访问速度。开始优化1.更改服务器DNS解析服务器由于Let's Encrypt证书DNS解析被污染，在服务器上也是无法直接访问Let's Encrypt的OCSP验证域名的，解决访问有两个一：我们更改服务器的DNS解析服务器为8.8.8.8等国外公共服务器二：直接修改本地Hosts，指定OCSP域名ocsp.int-x3.letsencrypt.org的IP地址这里我选择第二种，直接修改本地Hosts文件//编辑Hosts文件 vi /etc/hosts //添加如下信息 175.45.42.218 ocsp.int-x3.letsencrypt.org这里列举出来一些常用的ocsp.int-x3.letsencrypt.org服务器IP地址23.44.51.8 （美国） 23.44.51.27 （美国） 104.109.129.57 （英国） 104.109.129.11 （英国） 175.45.42.209 （香港） 175.45.42.218 （香港） 223.119.50.201 （香港） 223.119.50.203 （香港） 23.32.3.72 （东京）2.编写Shell脚本去获取OCSP响应直接在指定目录vim getOCSP.sh，输入以下脚本信息（仅在CentOS7 x64系统下实测过没问题，其他系统请自行测试）：#!/bin/sh SITE=$1 if [ ! $1 ]; then echo "请输入查询域名！正确打开方式：sh getOCSP.sh ffis.me" exit 0; fi # acme.sh 安装目录 LEDIR=/root/.acme.sh # 证书目录 DIR=$LEDIR/$SITE # Let's Encrype OCSP 服务器地址 HOST=ocsp.int-x3.letsencrypt.org # OCSP 响应保存文件地址 OUTDIR=/xxx/xxx/xxx/xxx/xxx/live # 日志文件地址 LOGFILE=$OUTDIR/log/get-ocsp_$(date +\%Y\%m\%d).log echo $(date +"%Y-%m-%d %H:%M:%S") '-----域名:'$SITE '开始请求OCSP响应------' >> $LOGFILE # 请求 ocsp 响应并保存到本地文件 openssl ocsp -no_nonce \ -respout $OUTDIR/$SITE.ocsp.resp.new \ -issuer $DIR/ca.cer \ -verify_other $DIR/ca.cer \ -cert $DIR/$SITE.cer \ -url http://$HOST/ \ -header "host="$HOST > $OUTDIR/$SITE.ocsp-reply.txt 2>&1 if grep -q ": good" $OUTDIR/$SITE.ocsp-reply.txt; then if cmp -s $OUTDIR/$SITE.ocsp.resp.new $OUTDIR/$SITE.ocsp.resp; then rm $OUTDIR/$SITE.ocsp.resp.new else mv $OUTDIR/$SITE.ocsp.resp.new $OUTDIR/$SITE.ocsp.resp # nginx 配置重载 systemctl force-reload nginx.service > /dev/null fi else cat $OUTDIR/$SITE.ocsp-reply.txt | echo "OCSP error for $SITE" fi # 输出到控制台 cat $OUTDIR/$SITE.ocsp-reply.txt # 输出到日志文件 cat $OUTDIR/$SITE.ocsp-reply.txt >> $LOGFILE # 记录最后一次OCSP请求结果 mv $OUTDIR/$SITE.ocsp-reply.txt $OUTDIR/$SITE.ocsp-reply-old.txt echo $(date +"%Y-%m-%d %H:%M:%S") '------------OCSP响应请求完毕------------' >> $LOGFILE我的这个脚本是针对 acme.sh 脚本而编写的，如果你使用的也是acme.sh，直接修改脚本中的：acme.sh安装目录：LEDIROCSP 响应保存文件地址：OUTDIR日志文件地址：LOGFILE并确保输入的目录已经创建好。如果要获取指定证书文件的OCSP响应，则需要自己手动修改对应的证书目录和OCSP服务器地址等。3.运行脚本//添加可执行权限 chmod +x getOCSP.sh //运行脚本 ./getOCSP.sh ffis.me //PS:后边的参数为需要获取OCSP响应的域名运行后就会在指定的目录生成OCSP响应文件了4.Nginx读取OCSP响应文件这时的Nginx配置就比上边的方式要简单许多了ssl_stapling on; ssl_stapling_verify on; //OCSP响应文件地址 ssl_stapling_file /xxx/xxx/xxx/xxx/xxx/live/ffis.me.ocsp.resp;重启Nginx后，OCSP响应的预加载就完成了这时再去检测下SSL证书状态5.配置crontab定时任务，每日自动刷新OCSP缓存虽然我们本地预加载了OCSP响应缓存，但是OCSP响应也是有生效时间了，超过有效时间就得重新获取，这里我们可以配置crontab定时任务去每日自动刷新OCSP响应缓存//编辑crontab定时任务 crontab -e //添加如下命令 #每日2:22分刷新OCSP缓存 22 2 * * * /root/getOCSP.sh ffis.me > /dev/null 2>&1这样crontab定时任务就配置完成至此我们的Nginx OCSP装订工作就到此完成~
记录下Docker快速搭建Redis的笔记1 查看可用的Redis版本docker search redis2 拉取Redis镜像docker pull redis:latest这里我使用的是官方最新版3 查看刚刚拉取的镜像docker images4 创建编辑Redis配置文件//创建redis本地配置文件目录 mkdir -p /data/docker/redis cd /data/docker/redis //下载配置文件 redis.conf wget http://download.redis.io/redis-stable/redis.conf //修改配置文件 vi redis.conf //修改前： bind 127.0.0.1 protected-mode yes appendonly no # requirepass foobared //修改后： # bind 127.0.0.1 protected-mode no appendonly yes requirepass testredis //配置说明 bind 127.0.0.1 //注释掉这部分，这里是限制redis只能本地访问 protected-mode no //默认yes，开启保护模式，限制为本地访问 appendonly yes //redis持久化（可选） requirepass testredis //设置访问密码为 testredis tips：protected-mode 是在没有显示定义 bind 地址（即监听全网断），又没有设置密码 requirepass 时，只允许本地回环 127.0.0.1 访问。 也就是说当开启了 protected-mode 时，如果你既没有显示的定义了 bind 监听的地址，同时又没有设置 auth 密码。那你只能通过 127.0.0.1 来访问 redis 服务5 部署镜像docker run -d \ -p 6379:6379\ -v /data/docker/redis/redis.conf:/usr/local/etc/redis/redis.conf \ --name redis\ --restart=always \ --privileged=true \ redis:latest redis-server /usr/local/etc/redis/redis.conf现在就可以看到刚刚启动的redis服务了docker ps -a6 使用客户端连接redis
有的时候需要快速搭建一个MySQL数据库，选择Docker当然是没错的辣~如果你之前配置过的话，一条命令就能快速的搭建起来一个MySQL数据库 1 查看可用的MySQL版本docker search mysql2 拉取MySQL镜像这里我需要安装MySQL 5.7版本的docker pull mysql:5.73 查看刚刚拉取的镜像docker images 4 创建MySQL的配置文件和数据存放目录MySQL(5.7.19)的默认配置文件是 /etc/mysql/my.cnf 文件。如果想要自定义配置，建议向 /etc/mysql/conf.d 目录中创建 .cnf 文件。新建的文件可以任意起名，只要保证后缀名是 cnf 即可。新建的文件中的配置项可以覆盖 /etc/mysql/my.cnf 中的配置项//创建配置文件存在目录并移动的该慕课下 mkdir -p /opt/docker/mysql/config && cd /opt/docker/mysql/config //创建配置文件 touch my.conf //创建数据存放目录 mkdir -p /www/data/mysqlData5 部署镜像docker run -d \ -p 3306:3306 \ --name mysql5.7 \ -v /www/data/mysqlData:/var/lib/mysql \ -v /opt/docker/mysql/config:/etc/mysql/conf.d \ -e MYSQL_ROOT_PASSWORD=123456 \ --restart=always \ --privileged=true \ mysql:5.7参数说明：-d // 后台运行 -p 3306:3306 // 将主机的3306端口映射到容器的3306端口 -v /www/data/mysqlData:/var/lib/mysql // 将主机的 /www/data/mysqlData 映射到容器的/var/lib/mysql，mysql的数据目录 -v /opt/docker/mysql/config:/etc/mysql/conf.d // 映射配置文件 -e MYSQL_ROOT_PASSWORD=123456 // 初始化数据库密码 --restart=always // 当Docker 重启时，容器会自动启动。 --privileged=true // 提升权限，拥有真正root权限，否则容器内root只是外部普通用户权限看刚刚启动的docker服务使用客户端连接MySQL服务器
不知不觉使用Material主题已经度过了四个年头，个人还是非常喜欢这个主题的，期间大大小小对主题进行了无数次的魔改，反正是有什么想法就想办法实现了，除非出现下一个更喜欢的主题或者自己动手做一个，目前来说还是会继续用这个主题的本站主题的魔改的代码已经在Github开源：https://github.com/noisky/typecho_material_theme.git开源主要是为了更新主题方便，直接在服务器上git pull就可以保持更新了... 所以并没有整理打包发布..想尝鲜的可以自己动手去改，主要是替换cdn的资源为本地即可最近的主要改动如下：清凉夏季配色大家应该可以看到网站的主题配色更改为清凉夏季配色，其实更改配色方案的想法很早就有了，只不过一直没有去实施主要是有好多细节性的需要调整；这次抽空给整理了下，把需要更改的属性值但单独的提取出来，并且定义统一的颜色变量去管理，这样就方便以后更改配色了这次只做了一套夏季配色，之后应该会做多套，按季度更换配色~ 当我什么都没说自适应黑暗主题除了更换了夏季配色，这次还做了一套黑暗配色~ 连微信都支持黑暗配色了，你的网站还不支持吗？主流浏览器已经支持黑暗配色的自动适应，也就是当系统主题配色为黑色时，网站将自动使用黑暗配色整体效果还是可以的，可能有些小细节没有调整到，往后再慢慢完善吧~主要是使用了媒体查询标签 prefers-color-scheme: dark@media (prefers-color-scheme: dark) { //黑色配色的css }这个标签会自动检测浏览器的主题，如多是黑暗主题自动切换到黑暗配色博客主题自动部署前一阵子研究了下自动构建，主要是使用 Gtiea+Drone 实现的，轻量化部署方便现在给主题也用上了自动构建之前主题是放在github上的，主题更新好服务器上是主动 git pull 同步的现在把主题的仓库同步到了 Gtiea，平时只修改gitea上的仓库，速度也快然后提交commit后，drone直接ssh远程登录到服务器执行git pull，并且把仓库同步到github的远程仓库中真·自动化 而我需要做的就是修改本地的代码，然后 git commit && git push 就行啦~这才是解放生产力~接入谷歌统计服务博客最近接入了谷歌统计服务，主要谷歌的统计分析更加全面多样化一点不过缺点是由于谷歌的服务速度不是很稳定，所以网站的加载速度被拖累了 这也是没有办法的事，现在网站在同时使用两套统计系统，等数据报告比较完善的情况下，我再对比看看最终使用哪一家的统计服务吧...首页DNS查询缓存博客的首页加载使用的dns查询缓存，理论上会给网站加速一丢丢..（真的假的我也感觉不出来）主要是看到淘宝也这么做了..具体就是在header.php的头标签上加上了这么一个判断<?php if($this->is('index')): ?> <?php endif;?>当然具体效果如何，这就是仁者见仁智者见智了 增加赞助页面网站的侧栏和关于页面加入了赞助入口，现在你可以请我喝杯咖啡了 文章页增加目录树这个功能其实早就想加了，原计划就是使用js去生成一个目录树但是在我逛github的时候偶然发现了大佬写好的有轮子了Github：https://github.com/xxyangyoulin/jquery_headindex自动生成文章目录索引，手风琴式折叠显示，自动定位当前位置完美符合我的预期效果就直接集成到了主题中了，再美化下前端显示，和Material主题完美适配就是显示位置有点尴尬，由于是双栏式主题，所以就显得没有地方塞这个目录树现在的方案是先在左侧显示，等侧边栏滚动出屏幕显示区域后，再将目录树移动到侧边栏的位置效果方面还是有点突兀，等待后续想出更好的方案再优化吧再次感谢大佬 @xxyangyoulin文章图片使用webp格式之前的文章图片比较大的我会手动的使用 tinypng.com 压缩一下，基本能达到比较理想的文件大小不过随着webp格式的普及，我也开启了又拍云的webp图片格式，这样在请求图片的时候，又拍云会检测客户端是否支持webp的图片格式而智能返回webp或者原图片格式，也算从侧边优化了网站的加载速度吧~使用Gzip和Brotli压缩又拍云现在上线了Gzip和Broli智能压缩，在客户端同时都支持 Gzip 和 Brotli 的情况下，又拍云会优先使用 Brotli 压缩算法很实用的功能更改文章永久链接地址这次终于铁了心了更改了文章的永久链接格式之前的格式是 ffis.me/分类/文章地址 的显示格式感觉风格不是很统一，想换成wp的格式 ffis.me/archives/文章地址一直没下决心去改，因为改了之后以前的链接都404了不过这次我编写了nginx规则，实现了301重定向，将以前几个分类的地址自动重定向到新的地址上这样以前的链接也能正常的引流到新的链接上了，一举两得，美滋滋 附上我的nginx重定向方案#文章永久路径跳转，只跳转分类+文章地址的访问，不跳转分类的访问 location ~ ^/Diary/..*$ { rewrite ^/Diary/(.*)$ /archives/$1 permanent; } location ~ ^/Music/..*$ { rewrite ^/Music/(.*)$ /archives/$1 permanent; } location ~ ^/experience/..*$ { rewrite ^/experience/(.*)$ /archives/$1 permanent; } location ~ ^/Share/..*$ { rewrite ^/Share/(.*)$ /archives/$1 permanent; } location ~ ^/java/..*$ { rewrite ^/java/(.*)$ /archives/$1 permanent; }首页banner的加载方式首页的banner大图的加载方式最开始是静态写在css中的后来我接入了我的随机图片api，这样更改图片就不用每次都修改css文件了，而且api是自己写的，想怎么展示都可以现在的方案是每日换一张图片，不过图片得自己适配，暂时只有四张图片，以后可能会加更多的图片不过图片多了反而也不太好，影响了整体观感后期可能会考虑根据配色确定图片，图片和配色做成配套的，这样效果也许会更好 近期对网站和主题做出的小改动大概就是以上这么多了，以后有其他想法了再慢慢折腾
活动持续一个星期，截止到5月21日 昨天开始领的时候，服务器直接给搞炸了，不管是中国站还是国际站都处于崩溃的状态，不过今天服务器逐渐恢复正常了，刚刚试了下可以领取了正所谓早买早享受，晚买享折扣，不买免费送；开局一个号，游戏全靠领!这下你还能说自己咩有GTA5？还不快叫上老友一起搞事情~并且Epic官方明确表示三周内不会免费商城已上线的游戏，也就是说不会背刺自己，但是只背刺你steam 作为吃瓜群众，还是欢快的看着平台神仙打架，坐等撸羊毛吧~
使用Gitea+Drone来搭建自己的轻量级CI/CD自动构建平台
上一次我们使用Gitea搭建了自己的Git版本控制系统，可以用来管理自己的代码还需要一个自动构建工具来解放生产力，这里我推荐使用Drone来搭建CI/CD持续集成，持续部署平台 为什么选用Gitea+Drone呢？因为这两款软件都是基于go编写的，运行过程中可谓十分轻量级，对于资源的占用都是很少的，并且都可以基于docker来安装，安装部署起来十分方便相对来说主流的Gitlab+Jenkins一套下来对于资源的占用，个人是很难能流畅运行的，至少我的机器连个Gitlab都跑不起来，更别提使用Java编写的Jenkins了。。。 废话少说，直接开搞~ 这里我的服务器环境使用的是最新的CentOS7 x64系统，只安装了一个docker1 安装GiteaGitea的安装过程详见：https://ffis.me/experience/1960.html这里就不做过多的阐述了2 安装Drone新版的Drone可以直接使用OAuto2和drone进行通信，无缝集成，配置完成后只需要得到gitea的授权即可进入drone平台，连账户和密码都不用输了2.1 Gitea创建OAuth2应用程序我们进入Gitea-->点击右上角头像-->设置-->应用-->管理OAuth2应用程序来创建一个OAuth2应用程序这里的重定向URL是授权成功后跳转到drone的地址，根据自己的drone地址来创建创建成功后就可以拿到客户端ID和客户端密钥了，这里可以先记录下来，我们后边会用到，因为一旦离开这个页面就没法再查看密钥了，只能重新生成2.2 创建共享密钥这里我们还需要创建一个共享密钥来供drone和docker-runner通信使用我们可以使用openssl生成共享密钥：$ openssl rand -hex 16 da7fb75c68106b563100bec5ce166b722.3 安装Docker Compose这里我使用Docker Compose来部署DroneDocker Compose是用来批量创建和管理Docker容器的，只需要配置好yml配置文件，就可以批量管理Docker容器安装过程可参考：https://www.runoob.com/docker/docker-compose.html2.4 编写docker-compose.yml文件这里我们通过使用 Docker Compose 来构建并启动 Drone和 Docker Runner，编写 docker-compose.yml 文件$ mkdir drone $ cd drone $ vim docker-compose.yml在配置文件中，我们设置 docker-compose.yml 的格式为 3 号版本，定义以下两个docker服务。Drone Server：使用drone/drone:1版本镜像，将 drone 容器的 80 端口映射到宿主机的 7079 端口。映射容器内 /data 目录到宿主机的 /data/drone 目录，以便 drone 可以保留数据。配置服务自动重新启动，并配置构建 drone 所需的环境变量。Docker Runner：使用 drone/drone-runner-docker:1 版本镜像，将 docker 启动句柄挂载到容器 /var/run/docker.sock 文件中，以便 drone 可以使用 docker-runner 来执行镜像构建任务。环境变量中需要配置 drone server 的端口协议以及共享密钥，以便与 server 进行通信。具体配置可参考如下配置：version: '3' services: # 容器名称 fan-drone-server: # 构建所使用的镜像 image: drone/drone:1 # 映射容器内80端口到宿主机的7079端口 ports: - 7079:80 # 映射容器内/data目录到宿主机的/data/drone目录 volumes: - /data/drone:/data # 容器随docker自动启动 restart: always environment: # Gitea 服务器地址 - DRONE_GITEA_SERVER=https://git.ffis.me # Gitea OAuth2客户端ID - DRONE_GITEA_CLIENT_ID=aaaaaaaaaaa-8888-8888-8888-fffffffffffff # Gitea OAuth2客户端密钥 - DRONE_GITEA_CLIENT_SECRET=aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbffffffff # drone的共享密钥 - DRONE_RPC_SECRET=asdfsadfasdfsadfsadfasdf # drone的主机名 - DRONE_SERVER_HOST=drone.ffis.me # 外部协议方案 - DRONE_SERVER_PROTO=https # 创建管理员账户，这里对应为gitea的用户名 - DRONE_USER_CREATE=username:noisky,admin:true fan-docker-runner: image: drone/drone-runner-docker:1 ports: - 7080:3000 restart: always depends_on: - fan-drone-server volumes: - /var/run/docker.sock:/var/run/docker.sock environment: # 用于连接到Drone服务器的协议。该值必须是http或https。 - DRONE_RPC_PROTO=https # 用于连接到Drone服务器的主机名 - DRONE_RPC_HOST=drone.ffis.me # Drone服务器进行身份验证的共享密钥，和上面设置一样 - DRONE_RPC_SECRET=asdfsadfasdfsadfsadfasdf # 限制运行程序可以执行的并发管道数。运行程序默认情况下执行2个并发管道。 - DRONE_RUNNER_CAPACITY=2 # docker runner 名称 - DRONE_RUNNER_NAME=fan-docker-runner-12.5 构建drone和runnerdocker-compose up -d -d 为后台运行这里我的drone使用的域名访问，是因为我配置了nginx反向代理，如果你没有配置也可以使用ip:端口的形式访问，一定要配置好域名再进行构建，不然会报错贴出我的drone的nginx反向代理配置，供参考location / { proxy_pass http://127.0.0.1:7079/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }2.6 打开drone到这里如果没有出问题的话drone就构建完成了，我们在浏览器输入配置的drone地址，可看到自动跳转到gitea的授权页面这里我们进行授权后就跳转到drone的页面了，只需授权一次即可，往后我们登录了gitea就直接进入drone了进入drone会看到未激活的仓库，我们点击激活它激活后回到gitea，我们会看到仓库已经自动配置好了web钩子我们可以进去测试钩子，一般是没问题的到这里我们的drone就安装完毕了，激活仓库后，我们向仓库推送一个commit，gitea就会发送消息通知drone去干活啦~3 配置Drone自动构建drone的安装过程还是很简单的，下面我们来进行drone构建的配置drone支持不同环境的不同管道配置，这里我使用Docker Pipelines管道配置简单来说就是drone的每一步操作都在一个临时的drone的容器中进行，容器操作完会自动销毁，容器之间会共享当前的工作目录这里我还是构建一个springboot工程，下面介绍两种部署方式：3.1 本地部署本地部署主要步骤：drone拉取最新的代码到当前工作目录drone创建maven/grade容器，通过指定的构建工具maven/grade等将代码编译/打包为jar包，然后将jar包和Dockerfile文件复制到挂载的宿主机共享目录中drone创建ssh容器，在容器中通过ssh连接到宿主机，通过定义好的命令，到jar和Dockerfile目录中将jar包制作构建为镜像，然后通过镜像创建应用容器并运行，期间会删除之前老的应用程序容器和镜像drone创建钉钉通知容器，将构建成功/失败的消息通过钉钉机器人通知到管理员至此本地构建完毕，这个构建步骤是我自己搞的，其优点是所有操作都在本机执行，构建的应用不用经过网络传输，整体部署的速度很快，其缺点是只能单机部署，无法进行分布式多机器部署，如果自己个人单机使用的话推荐使用这种方式，我的测试demo，整体部署流程下来只用了12s，速度还是很快的编写drone部署的文件在仓库的根目录下创建.drone.yml配置文件配置文件参考如下配置：# drone 本地构建 kind: pipeline type: docker name: MyHelloWorld # drone构建步骤 steps: # 1.maven打包 - name: maven compile pull: if-not-exists image: maven:ibmjava-alpine volumes: # maven构建缓存 - name: cache path: /root/.m2 # 挂载宿主机的目录 - name: data path: /home commands: # 开始打包maven工程 - cd demo - mvn clean package -Dmaven.test.skip=true # 将打包后的文件复制到宿主机映射目录 - cp target/*.jar /home - cp ../Dockerfile /home # 2.使用ssh访问主机制作镜像并运行 - name: ssh commands pull: if-not-exists image: appleboy/drone-ssh:1.5.7 settings: host: 0.0.0.0 username: root password: # 从drone仓库配置中秘密空间读取密码 from_secret: ssh_password port: 22 script: - echo =======暂停容器======= - docker stop `docker ps -a | grep springdemo | awk '{print $1}' ` - echo =======暂停旧容器和镜像======= - docker rm -f `docker ps -a | grep springdemo | awk '{print $1}' ` - docker rmi `docker images | grep springdemo | awk '{print $3}' ` - echo =======开始构建新镜像======= - cd /data/drone/helloDemo - docker build -t springdemo:v1 . - echo =======开始部署应用======= - docker run -d -p 8188:8180 --name springdemo springdemo:v1 - echo =======清理构建文件======= - rm -rf * - echo =======部署成功======= # 3.钉钉通知 - name: dingTalk notification pull: if-not-exists image: guoxudongdocker/drone-dingtalk:latest settings: token: from_secret: dingtalk_token type: markdown message_color: true message_pic: true sha_link: true when: status: [failure, success] # 挂载的主机卷，可以映射到docker容器中 volumes: # maven构建缓存 - name: cache host: # path: /tmp/cache/.m2 path: /var/lib/cache # maven构建后与宿主机通信的共享目录 - name: data host: path: /data/drone/helloDemo # drone执行触发器 trigger: branch: - master文件编写完成后，git push到仓库中，gitea会通知drone进行部署，drone找到.drone.yml配置文件，就会按照配置文件中的步骤进行构建了，部署期间可以在drone中查看到每一步的部署情况3.2 分布式云部署云部署主要步骤：drone拉取最新的代码到当前工作目录drone创建maven/grade容器，通过指定的构建工具maven/grade等将代码编译/打包为jar包，然后将打包完成后的jar移动到根目录，也就是工作目录drone创建docker构建容器，将jar通过dockerfile指定的方式构建为镜像，然后将构建完成的镜像上传到腾讯云/阿里云私有仓库中drone创建ssh容器，通过ssh连接到一个或多个主机，然后批量从私有仓库中拉取最新镜像进行部署drone创建钉钉通知容器，将构建成功/失败的消息通过钉钉机器人通知到管理员这种方式配置较为简单，所有操作都在docker中进行，没有和主机通讯，并且构建好的镜像直接推送到第三方私有仓库中的，期间会通过网络传输，多多少少都会耗费点时间；不过好在同一服务商的私有仓库都是通过内网进行访问的，访问速度影响可忽略不计；而且有很大的优化空间，毕竟我们写的代码只有几百k的大小，其中的系统层、jdk层、lib依赖库层，基本上代码都是不变的;所以可以通过对docker镜像进行分层构建，分层推送，通过缓存的加速也是可以做到秒级推送，这样每次更新的就只有我们写的代码，传输的数据量就很少了，不过这个属于比较高级的应用了，我们这里先不研究了；云部署主要好处是可以做到分布式部署，多个主机可以从私有仓库中拉取最新镜像，实用性还是很高的。编写drone部署的文件同样也是在仓库的根目录下创建.drone.yml配置文件参考如下配置：# drone 云部署 kind: pipeline type: docker name: MyHelloWorld # drone构建步骤 steps: # 1.maven打包 - name: maven compile pull: if-not-exists image: maven:ibmjava-alpine volumes: # maven构建缓存 - name: cache path: /root/.m2 commands: # 开始打包maven工程 - cd demo - mvn clean package -Dmaven.test.skip=true # 将打包后的jar包移动到 Dockerfile 文件同级目录 - mv target/demo-0.0.1-SNAPSHOT.jar ../demo-0.0.1-SNAPSHOT.jar # 2.Docker 制作镜像，推送到私有仓库 - name: docker build image: plugins/docker pull: if-not-exists volumes: - name: docker path: /var/run/docker.sock settings: username: username password: from_secret: dockerHub_password tags: - latest repo: ccr.ccs.tencentyun.com/fanfan/hellodemo registry: ccr.ccs.tencentyun.com dockerfile: Dockerfile # 3.使用ssh访问主机运行最新版容器 - name: ssh commands pull: if-not-exists image: appleboy/drone-ssh:1.5.7 settings: host: 49.234.106.44 username: root password: from_secret: ssh_password port: 22 script: - echo =======暂停容器======= - docker stop `docker ps -a | grep springdemo | awk '{print $1}' ` - echo =======暂停旧容器======= - docker rm -f `docker ps -a | grep springdemo | awk '{print $1}' ` - echo =======开始部署应用======= - docker run -d -p 8188:8180 --name springdemo --restart=always ccr.ccs.tencentyun.com/fanfan/hellodemo:latest - echo =======部署成功======= # 4.钉钉通知 - name: dingTalk notification pull: if-not-exists image: guoxudongdocker/drone-dingtalk:latest settings: token: from_secret: dingtalk_token type: markdown message_color: true message_pic: true sha_link: true when: status: [failure, success] # 挂载的主机卷，可以映射到docker容器中 volumes: # maven构建缓存 - name: cache host: # path: /tmp/cache/.m2 path: /var/lib/cache - name: docker host: path: /var/run/docker.sock # drone执行触发器 trigger: branch: - master编写好部署的配置文件，推送到仓库中，drone就行按照配置的步骤进行部署了首次部署的速度可能略慢，我这里用了50s，不过等仓库缓存变热之后速度就上来了，这里我用了33s总体很是可以接受的，如果进行分层构建优化的话，应该还会再快，不过还是和本地部署的速度没得比，这里根据自己的需要选择不同的部署方式即可，并且不同语言的应用部署的方式是不一样的，可以定制属于自己的部署方式部署成功后的钉钉通知页面4 资源占用Gitea和Drone都是基于go语言编写的，其优点是轻量级，占用资源较少，下面为部署了gitea和drone后的资源占用可以看到总占用也不到200M的内存，相比传统的gitlab+Jenkins非常轻量化了，并且该有的功能都有，如果用户数不是很大的话，还是很推荐大家使用的 自动部署一旦配置好了，所有的编译/测试/打包/部署的工作就交给drone去完成了，而我们只需要专注于我们的代码编写就行了，是不是特别爽呢？还不快去搭建一个属于自己的自动构建平台吧~
Dcoker是一个开源的应用容器引擎，介绍我就不介绍了，总之就是很牛批，用过的都相见恨晚 平时我们不是应用都是先搭建相关环境，然后把应用启动一通配置好本地环境需要搭建一次，测试环境需要搭建一次，生产环境也需要搭建一次，这样重复的工作就做了几次，效率降低 使用了docker了？我们只需要构建一次镜像，然后不同的环境只需要把镜像拉下来启动就行了，是不是很简单？如果配合CI/DI持续集成，持续部署，那就太爽歪歪了，我们只需要把代码提交到git，剩下打包/编译/测试/部署工作就全自动自己运行了，是不是大大提高了生产力？ 废话不多说，今天先研究docker怎么构建SpringBoot，改天再研究CI/DI~1 安装Docker首先docker只支持CentOS7以上的系统，如果系统版本过低请升级系统这里我使用的是CentOS7 x64docker安装教程详见：Docker的基本操作与使用2 准备SpringBoot应用这里我们使用idea来快速构建一个SpringBoot应用简单编写一个HelloController@RestController public class HelloController { @RequestMapping("/hello") public Object hello() { return "hello World!!!"; } }右键启动类运行，浏览器输入 http://localhost:8080/hello 可以看到启动成功3 创建Dockerfile构建文件我们创建docker文件夹，并在里面创建Dockerfile构建文件$ mkdir docker $ cd docker $ vim Dockerfile编写Dockerfile文件# Docker image for springboot file run # VERSION 0.0.1 # Author: Noisky # 基础镜像使用openjdk:8 FROM openjdk:8u181-jdk-alpine # 作者 MAINTAINER Noisky <noisky@ffis.me> # VOLUME 指定了临时文件目录为/tmp。 # 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件，并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更名为app.jar ADD demo-0.0.1-SNAPSHOT.jar app.jar # 运行参数 ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]4 制作SpringBoot镜像将打包好的jar包放入docker文件夹，使docker文件夹只有Dockerfile和需要打包的jar文件docker安装并启动后，我们来制作SpringBoot镜像cd 进入docker目录运行以下命令来制作镜像，注意最后的.docker build -t springdemo:v1 . -t 参数是指定此镜像的名称如图所示开始制作，最后的.表示当前目录，也就是构建镜像的上下文路径。提示successfully表示构建成功这时候我们可以使用 docker images 来查看构建的镜像了5 从新镜像启动容器docker run -d -p 8188:8180 --name springdemo springdemo:v1 -d 参数是让容器后台运行 -p 是做端口映射，此时将服务器中的8188端口映射到容器中的8080(项目中端口配置的是8080)端口运行成功现在的SpringBoot应用是使用docker构建并管理运行的我们可以使用新端口来访问试试
一直以来都想搭建自己的版本控制系统，虽然现在又Github、Gitee等热门的公共Git系统了，可有时候还是需要一个私有的Git系统来更方便的去管理、控制代码这里我看了下开源的Git软件，大致有Gitlab、Gogs、Gitea等几款软件，Gitlab功能比较强大，但是个人使用就略显臃肿了，个人我还是倾向于使用比较轻量化的软件的，毕竟服务器的资源有限，能满足自己的需求就行了Gitea是Gogs的一个分支，两款都是比较轻量化的软件，gogs之前搭建过了，这里选用Gitea再次搭建一个自己托管的Git版本控制中心。docker安装Gitea是支持使用docker安装的，所以安装的步骤和过程都很简单明了1.创建gogs数据储存目录mkdir -p /data/gogs2.拉取最新版镜像docker pull gitea/gitea:latest3.运行docker容器docker run -d --name=gitea -p 10022:22 -p 10080:3000 -v /data/gitea:/data gitea/gitea:latest -d: 后台运行 --name: docker容器名称 -p: 端口映射，将容器端口3000 映射到宿主机的 10080端口 -v: 目录映射，将容器 /data 目录映射到宿主机的 /data/gitea 目录 gitea/gitea:latest: 使用的docker镜像这样我们就是用docker安装好了一个Gitea服务，现在可以直接在浏览器使用10080端口来访问我们的Gitea服务了记得防火墙开放 10080 端口http://x.x.x.x:10080初始化Gitea安装完成后，点击右上角的登录，即可进入Gitea的初始化页面官方文档：https://docs.gitea.io/zh-cn/install-with-docker/nginx反向代理使用ip+端口访问显然不是我们想要的方式，可以使用nginx反向代理，将域名转发到指定端口的服务即可编辑nginx配置文件，添加如下配置，其中端口为你的gitea所提供的端口：location / { proxy_pass http://127.0.0.1:10080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }资源占用以下为gogs和gitea的系统资源占用情况从左到右依次为应用名称、cpu占用、内存占用、内存百分比可以看出gogs是最省内存的，运行只占用内存35m左右而gitea相比gogs内存占用比较多一点，运行占用内存133m左右两款软件对比gitlab都属于轻量级软件，只需很轻量的配置就可以跑起来至此我们自己托管的git服务就搭建完毕了 具体的一些高级配置可以参考官方文档~