首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

阿里云部署Hugo与备案实践

  • 25-04-18 18:41
  • 4701
  • 6839
juejin.cn

如需更优质的阅读体验,欢迎访问个人站点。原文地址

前言

想了老半天终于还是把博客搬到国内服务器上了,简单的记录一下搬迁过程。主要记录了证书申请&管理,nginx部署,顺便附带一些服务器管理和防爆破的小技巧。

部署实践

环境准备

服务器

从阿里云购买云服务器一台,配置如下:

  • 实例规格: ecs.e-c1m1.large
  • CPU: 2vCpu
  • 内存: 2GiB
  • 带宽: 3Mbps
  • 存储: 40GiB
  • 操作系统: Alibaba Cloud Linux 3.2104 LTS 64位 UEFI版

我在安装操作系统时选了禁止root登录,所以需要知道root和ecs-user密码,其中root密码用于执行sudo命令。

因为是需要作为网站的入口使用,所以需要开放80和443端口。具体步骤为 实例详情页-进入安全组tab-管理规则,在规则管理页面,添加入方向的80和443规则,开放给所有IP。可以点击快速添加,勾选80和443。 开放安全组

执行命令hostnamectl set-hostname ${HOST_NAME},其中HOST_NAME更换为需要更改的主机名 修改后可通过 hostname 验证,并重启验证是否永久生效

Nginx

使用nginx作为站点的HTTP容器。

登录服务器后,执行 sudo yum install nginx 进行安装,遇到提示后按y表示同意安装,如果需要输入root密码则输入root密码。

输入命令 nginx -v 来验证nginx是否安装完成,输出版本即为安装完成,比如我安装的是 1.20.1 ,则输出为 nginx version: nginx/1.20.1。

输入命令sudo nginx,来启动nginx。可以通过 ps -ef|grep nginx 命令来验证进程是否启动。如正常启动,可以看到一个root用户启动的master进程和若干个nginx用户启动的worker进程。(数量取决于核心数,由配置项 worker_processes auto; 控制) 如果需要在浏览器中验证页面是否可以访问,需要在阿里云的安全组中放行80端口。可以访问的话可以在浏览器中看到一个经典的Nginx小白页面。

Hugo部署

首先,需要规划一下我们网站部署的目录,以便修改nginx的配置。这里简单介绍一下nginx如何配置静态网站。我们的网站都被打包成静态文件放在服务器的某个目录里,而nginx可以通过指定root到这个目录来实现访问,网站的入口就是这个目录的index.html 。在Hugo中,这个目录就是运行hugo server后生成的 public/ 目录。所以,部署只需要把 public/ 目录放到服务器上,然后修改nginx的配置文件就好,网站的更新也只需要更新这个目录,而不需要修改nginx配置。 但是考虑到增量部署的场景,不断在目录中更新是也可以解决文件的新增和修改,无法删除文件。所以,在我的规划中,我每一次的部署都会放一个将打包出来的内容放到一个新的目录中。为了不修改nginx的配置,并保证目录切换的时间足够短(提供高的可访问性,虽然必要性不大),我对比了三个方案,最终选择在自动部署方案中采用了软链接的方式。

  • 先删除后上传:上传时间较长,会有比较长时间的一段无法提供服务的时间

  • 先上传后删除:一个相当比较好的方案,具体步骤为 上传新版本-删除老版本-重命名新版本,但是上一个版本删除后无法回滚,不过一般也用不到,再部署修复即可。(这里也可以把删除老版本改为重命名,但是依然需要做历史版本的管理)

  • 软链接:具体步骤为 上传新版本-修改软链接-删除老版本。在更新了软连接好就可用了。

    其实使用git更新也是一个非常好的方案,维护成本也不高。只是长期使用git的历史堆积会使得文件夹变得比较大,需要定期清理历史版本信息来控制文件大小。

    最初方案下图所示: 部署方案

    /website、/website/data 、 /website/data/blog_xxx 的属主为ecs-user,权限为755,需要保证nginx的读和部署用户ecs-user的读写。

nginx配置修改

按照规划,更改nginx的配置,在 /etc/nginx/default.d/ 下新建文件 blog.conf 输入以下内容:

conf
代码解读
复制代码
server_name ${YOUR_DOMAIN} # 替换为自己的域名 location / { root /website/blog/; index index.html; }

这段配置用于将root指向 /website/blog 目录,同时,需要删除原本 nginx.conf 中的内容,注释即可,可参考以下代码。

conf
代码解读
复制代码
listen 80; listen [::]:80; #server_name _; #root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; #error_page 404 /404.html; # location = /40x.html { #} #error_page 500 502 503 504 /50x.html; # location = /50x.html { #} }

还需要更改 nginx.conf 中的user为 /website/blog 目录的属主。

手动部署

手动部署不做赘述,将本地的 public/ 拉到服务器的 /website/blog 目录下就可以看到网站了(注意,是要用 hugo serve 重新生成过的,不是开发的直接拿上去)。

自动部署(CI/CD集成)

自动部署要做的事情其实不也复杂,就是在Github Action中添加一步,把 public/ 部署到服务器上,然调用服务器上的脚本就可以了。 先来写一个脚本,用于实现软链接的创建/更新和历史版本数量的管理,脚本位于服务器的某个目录就可以了,我放在了 ~/scripts/ 下。

bash
代码解读
复制代码
#!/bin/bash # 指定目录路径 DIRECTORY="/website/data/blog" # 软连接路径 SOFT_LINK="/website/blog" # 获取所有符合 blog_xxxx 格式的目录,并按创建时间排序 directories=($(ls -d "$DIRECTORY"/blog_* | xargs -I {} stat --format '%Y {}' {} | sort -n | cut -d' ' -f2-)) # 获取目录数量 num_directories=${#directories[@]} # 如果存在目录,则更新或新建软连接到最新创建的目录 if [ $num_directories -gt 0 ]; then latest_directory=${directories[-1]} echo "将使用目录 $latest_directory 作为工作目录" # 如果软连接不存在,则新建软连接 if [ ! -L "$SOFT_LINK" ]; then ln -s "$latest_directory" "$SOFT_LINK" else # 如果软连接已存在,则更新软连接 ln -sfn "$latest_directory" "$SOFT_LINK" fi fi # 如果目录数量大于2,则删除最早创建的目录,直到只剩下2个 while [ $num_directories -gt 2 ]; do # 删除最早创建的目录 echo "删除目录 ${directories[0]}" rm -rf "${directories[0]}" # 更新目录列表 directories=("${directories[@]:1}") num_directories=$((num_directories-1)) done # 如果目录数量少于或等于2,不需要进一步操作 if [ $num_directories -le 2 ]; then echo "目录数量符合要求,无需进一步操作。" else echo "操作完成,现在目录数量为 $num_directories。" fi chmod -R 755 "$DIRECTORY"/blog_*

写好部署脚本之后,需要添加执行权限 chmod +x deploy_blog.sh ,然后,更新一下Github Action的流水线定义文件,添加了两个步骤。

yaml
代码解读
复制代码
# Sample workflow for building and deploying a Hugo site to GitHub Pages name: Deploy Hugo site to Pages on: # Runs on pushes targeting the default branch push: branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false # Default to bash defaults: run: shell: bash jobs: # Build job build: runs-on: ubuntu-latest env: HUGO_VERSION: 0.139.3 steps: - name: Get current date id: gen-id run: echo "::set-output name=time::$(date +'%Y%m%d%H%M%s')" - name: Install Hugo CLI run: | wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ && sudo dpkg -i ${{ runner.temp }}/hugo.deb - name: Install Dart Sass run: sudo snap install dart-sass - name: Checkout uses: actions/checkout@v4 with: submodules: recursive - name: Install Node.js dependencies run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" - name: Build with Hugo env: HUGO_CACHEDIR: ${{ runner.temp }}/hugo_cache HUGO_ENVIRONMENT: production run: hugo --baseURL=https://www.zanks.link/ - name: Deploy Pages uses: peaceiris/actions-gh-pages@v3 with: PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }} EXTERNAL_REPOSITORY: ZaNksC/ZaNksC.github.io PUBLISH_BRANCH: main PUBLISH_DIR: ./public commit_message: ${{ github.event.head_commit.message }} - name: scp ssh pipelines uses: cross-the-world/ssh-scp-ssh-pipelines@latest with: host: ${{ secrets.HOST }} port: ${{ secrets.PORT }} user: ${{ secrets.USER }} key: ${{ secrets.PWD }} scp: | ./public/* => /website/data/blog/blog_${{ steps.gen-id.outputs.time }} last_ssh: | /home/ecs-user/scripts/deploy_blog.sh

${{ secret.HOST }} 等三个变量,则需要在Github代码仓 - settings -Secrets And variables - Actions 中添加,分别表示 IP地址、ssh端口(如果改过)、部署用户和部署用户登陆凭证(密码用 pass: ${{ VAR }} , 密钥用 key: ${{ VAR }}, 推荐用密钥)。

SSL证书(可选)

觉得没有小绿锁没有格调,又觉得有了小绿锁续签太过麻烦?没关系,接下来就教你从申请到配置再到自动续签的全过程。

SSL证书将通过acme.sh客户端向Let's Encrypt申请(免费!!!)。

acme.sh 是一个优秀的证书管理客户端。可以非常简单的做到申请与续签。

登录服务器,找一个目录,安装 acme.sh ,我是在 /home/ecs-user/scripts 下,输入以下命令(国内版)进行安装。[email protected] 替换为自己的邮箱(没有git的话,sudo yum install git 来安装)。

bash
代码解读
复制代码
git clone https://gitee.com/neilpang/acme.sh.git cd acme.sh ./acme.sh --install -m [email protected]

输出OK表示已经安装完成了。当然,也可以输入 ./acme.sh version 来查看版本来验证。

在安装过程,acme完成了三件事情

  • 在 ~/.acme.sh/ 目录下完成了安装
  • 在 ~/.bashrc 中新增了一行,用于配置别名,可以在任意目录输入 acme.sh 命令(需要 source ~/.bashrc 或重新登录生效)
  • 创建了一个crontab的任务,用于检测即将过期的证书来实现自动续签,可以通过命令 crontab -l 查看

安装完成之后,因为acme的默认证书签发机构不是Let's Encrypt所以需要手动配置一下。输入命令 acme.sh --set-default-ca --server letsencrypt 来完成配置。当然,也可以在申请命令中添加 --server letsencrypt 来指定机构。

接下来就是主题了,开始申请证书。在申请证书的过程中,机构会验证我们是否为域名的主人,在泛域名证书 *.zanks.link (以下命令中替换为自己的域名)的申请中,只能使用DNS方式来验证。输入以下命令来使用dns验证方式申请证书。

bash
代码解读
复制代码
acme.sh --issue --dns -d *.zanks.link \ --yes-I-know-dns-manual-mode-enough-go-ahead-please

执行完成之后,会提示需要添加一条TXT的解析记录。添加完成之后,根据DNS解析时间等待一段时间(NameSilo的解析实在是太慢了,改用腾讯之后体验非常好,秒解析),建议等待半小时,然后执行以下命令。

bash
代码解读
复制代码
acme.sh --renew -d *.zanks.link \ --yes-I-know-dns-manual-mode-enough-go-ahead-please

申请证书也可以通过域名商API的方式,参考 【官方文档】 (我试了一下没成功,感觉是网络问题) 申请成功后会出现4个文件,分别是 domainname.cer 、 domainname.key 、 ca.cer 、 fullchain.cer。主要使用的是 fullchain.cer 文件和 domainname.key 文件。fullchain.cer 提供了完整的证书链,而 domainname.key 是用于解密由客户端发送的加密数据的私钥。

证书生成之后,安装到nginx,不要手动去拷贝,使用以下命令。

bash
代码解读
复制代码
acme.sh --install-cert -d *.zanks.link \ --key-file /home/ecs-user/.acme.sh/*.zanks.link/*.zanks.link.key \ --fullchain-file /home/ecs-user/.acme.sh/*.zanks.link/fullchain.cer \ --reloadcmd "service nginx force-reload"

其中 --key-file 的参数修改为 domainname.key 的文件路径,--fullchain-file 的参数修改为 fullchain.cer 的文件路径。

之后就是修改nginx的配置开启443端口,代码如下:

conf
代码解读
复制代码
server { listen 443 ssl http2; listen [::]:443 ssl http2; #server_name _; #root /usr/share/nginx/html; ssl_certificate "/path/to/fullchain.cer"; ssl_certificate_key "/path/to/domainname.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers PROFILE=SYSTEM; ssl_prefer_server_ciphers on; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; #error_page 404 /404.html; # location = /40x.html { #} #error_page 500 502 503 504 /50x.html; # location = /50x.html { #} }

保持了跟http一样的配置,只是新增了一些ssl相关的配置,只需要将 fullchain.cer 和 domainname.key 的文件路径替换成之前申请出来的即可。

{{}} 配置好https之后,如果希望只能通过https访问,那么可以通过重定向配合HSTS来告诉浏览器使用https。需要修改 /etc/nginx/nginx.conf 来实现。

conf
代码解读
复制代码
server { listen 80; listen [::]:80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate "/path/to/fullchain.cer"; ssl_certificate_key "/path/to/example.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 10m; ssl_ciphers PROFILE=SYSTEM; ssl_prefer_server_ciphers on; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; include /etc/nginx/default.d/*.conf; }

{{}}

最后,就是在DNS解析中添加一条A记录,用于指向服务器。

DNS解析实践

由于服务器是没有IPv6地址的,为了使得网站支持IPv6,我在域名的解析规则中保留了Github Pages的IPv6站点。 最终,我的DNS解析规则(最后发现提交不了那么多条,腾讯云免费版的可解析条目有限,按需选择了)就是

subdomaindomainTypeValue
zanks.linkA我的服务器ip
wwwzanks.linkA我的服务器ip
zanks.linkAAAA2606:50c0:8000::153
wwwzanks.linkAAAA2606:50c0:8000::153
zanks.linkAAAA2606:50c0:8001::153
wwwzanks.linkAAAA2606:50c0:8001::153
zanks.linkAAAA2606:50c0:8002::153
wwwzanks.linkAAAA2606:50c0:8002::153
zanks.linkAAAA2606:50c0:8003::153
wwwzanks.linkAAAA2606:50c0:8003::153

通过 nslookup www.zanks.link 可以看到返回1个IPv4地址(自己的服务器地址)和多个IPv6地址(Github Pages)。

同时,分别通过 curl www.zanks.link 和 curl -6 www.zanks.link 可以验证IPv4和IPv6的访问。

域名备案

当我们的服务器是国内IP时,要求域名进行备案,否则会无法使用。

国外注册商无法通过备案,需要转到国内

域名转移

我是在NameSilo上买的域名,已转入腾讯云。

首先,需要在NameSilo上解锁域名+获取转移码。转移码的获取可以通过点击 Send Email ,而且需要等到60天之后才可以转移。(为此拖延了好几个月才备案)

域名备案

ICP备案

ICP备案需要在服务器所在的云服务商处发起备份,比如我的域名在腾讯云管理,服务器却在阿里云,我是从阿里云发起的ICP备案。发起是比较简单的,按照规范填好订单直接发起即可,发起后会有专员审核,帮你修改掉简单的错误就提交到管理局了(有一个比较麻烦的是需要拍一个读保证书的视频)。如果有无法通过的则会退回来,比如之前是在NameSilo买的域名没办法备案。提交申请快的话一天就可以,提交之后会收到一个管理局的短信去阿里云备案流程里面输入一下,然后等审批就好。

备案第一次失败了,退回原因为,该网站备案在审核通过前网站已开通,把DNS的解析关了之后重新提交。

公安备案

公安备案需要在ICP备案完成后的30天内进行(不知道不备案会有什么后果,查了一下可能会切断dns解析)。按照阿里云给出的文档,在全国互联网安全管理平台申请主体(需要下载一个app做人脸认证),需要准备 身份证正面、身份证反面、手持身份证照片、网站域名证书等材料。

公安的备案相当麻烦,需要关闭评论等功能,提交之后会当地负责网安的民警来协助你,需要你提交材料,如实回答,如实禀报即可。(就是评论功能这块,需要验证能发送的人每个人都实名有点为难个人博客了)

番外:服务器安全加固

fail2ban

用于防止暴力密码破解,在高位端口被扫到后,黑客会进行暴力密码破解,即便是IP代理池进行破解,代理池中的IP也是有限的,可以通过暴力拆解多次失败后将IP加入黑名单来提高黑客的破解成本,毕竟小破服务器也没什么值得人家大张旗鼓破解的必要,别人也只想要个肉鸡。所以这个操作可以有效防止黑客的暴力密码破解。

安装

输入命令进行安装

bash
代码解读
复制代码
sudo yum install fail2ban

通过以下命令管理fail2ban

bash
代码解读
复制代码
sudo systemctl status fail2ban # 查看状态 sudo systemctl start fail2ban # 启动服务 sudo systemctl stop fail2ban # 停止服务 sudo systemctl restart fail2ban # 重启服务

配置

fail2ban的配置位于 /etc/fail2ban 目录下,通常自定配置写在 /etc/fail2ban/jail.local 中,使用命令复制 jail.conf 来自定义配置,进行微调。

bash
代码解读
复制代码
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

可以使用命令 sudo fail2ban-client status 来检查fail2ban的配置

编辑 jail.local ,找到 [sshd] 模块进行修改。其中port如果改过,需要设置为配置的端口。

ini
代码解读
复制代码
enabled = true port = 22222 filter = sshd logpath = /var/log/secure maxretry = 5 findtime = 5m bantime = 4h

修改后重启服务,并查看配置可以看到有一条生效的。

yaml
代码解读
复制代码
sudo fail2ban-client status Status |- Number of jail: 1 `- Jail list: sshd

登录选项设置

设置ssh登录方式为禁止root登录。由于机器需要使用Github Action进行部署,暂时无法禁用密码登录(实际上是可以的)

修改 /etc/ssh/sshd_config 中的 PermitRootLogin yes 为 PermitRootLogin no 。 重启ssh服务 sudo systemctl restart sshd

高位端口

将ssh端口设置为高位端口,可以预防大部分的常规扫描。

修改 /etc/ssh/sshd_config 中的 #port 22 为 port 22222 或其他端口。 重启ssh服务 sudo systemctl restart sshd

检查登录日志

查看ssh登录失败日志

bash
代码解读
复制代码
sudo cat /var/log/secure | grep "Failed"

查看failed2ban的日志

bash
代码解读
复制代码
sudo cat /var/log/fail2ban.log
注:本文转载自juejin.cn的剥龙虾大王的文章"https://juejin.cn/post/7493879367728365578"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

142
代码人生
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top