# Hugo 简介 Hugo 是一个开源的静态站点生成器,支持通过 Markdown 文件快速生成静态 HTML 页面。其主要优势包括: 1. **构建速度快**:Hugo 采用 Go 语言开发,单线程构建速度极快,适合处理大规模内容。 2. **灵活性强**:支持多种主题和模块化设计,用户可根据需求定制站点外观与功能。 3. **易于部署**:生成的静态文件可直接托管于任意 Web 服务器,无需复杂的后端支持。 4. **学术友好性**:Hugo 支持 Markdown 格式,与学术写作常用的编辑工具(如 Obsidian)无缝衔接,便于内容管理和版本控制。 # 官网导航 [官方网站](https://gohugo.io/) [官方论坛](https://discourse.gohugo.io/) [中文官网](https://hugo.opendocs.io/) # 流程概览 Obsidian (创作) → Hugo (本地预览) → Git (推送至 GitHub) → GitHub Actions (自动编译部署) → Nginx (静态服务) → Cloudflare (全球加速与HTTPS) → 全球用户访问 # 站点初始化 ```shell # 创建一个新的 Hugo 站点,命名为 404-blog hugo new site 404-blog # 进入新创建的站点目录 cd 404-blog # 初始化 Git 仓库,用于版本管理和代码托管 git init # 设置 Git 的提交用户信息 git config user.name "404" git config user.email "404@example.com" # 暂存所有文件,准备提交 git add . # 提交更改,记录初始化的站点结构 git commit -m "Initial commit" # 添加 Hugo PaperMod 主题作为 Git 子模块,方便管理和更新主题 git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod # 在配置文件 hugo.toml 中设置主题为 PaperMod echo "theme = 'PaperMod'" >> hugo.toml # (此处手动添加 .gitignore 文件,用于忽略不必要的文件,如 node_modules 或临时文件) # 暂存所有更改,包括主题和 .gitignore 文件 git add . # 提交更改,记录主题和忽略文件的添加 git commit -m "Add PaperMod theme and .gitignore file" # 启动 Hugo 本地服务器,预览站点效果 hugo server ``` 其中 `.gitignore` 可参考 `PaperMod` 作者提供的文件。 ``` # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test /public .DS_Store .hugo_build.lock resources/_gen/ ``` # 自动化部署与服务器配置 要实现每次推送到 GitHub 仓库时,自动构建 Hugo 博客并部署到云服务器的 Nginx 下,需要完成以下步骤: ## 1. 准备云服务器 首先,确保您的云服务器已安装 Nginx: ```bash # Ubuntu/Debian sudo apt update && sudo apt full-upgrade -y sudo apt install nginx ``` ## 2. 配置 Nginx 修改 Nginx 主配置文件: ```nginx # --- 基本运行环境配置 --- user www-data; # 指定 Nginx 运行的用户,确保权限安全 worker_processes auto; # 自动匹配 CPU 核心数,优化并发处理 worker_cpu_affinity auto; # 自动绑定 CPU 核心,提升缓存命中率 pid /run/nginx.pid; # 定义主进程 ID 文件路径 error_log /var/log/nginx/error.log warn; # 设置错误日志路径及警告级别 include /etc/nginx/modules-enabled/*.conf; # 引入额外的模块配置文件 # --- 事件处理模块配置 --- events { worker_connections 1024; # 每个进程最大连接数,适配中型流量 multi_accept on; # 启用多连接同时接受,提升并发效率 use epoll; # 使用 epoll 事件模型,优化高并发性能 } # --- HTTP 服务核心配置 --- http { # 性能优化参数 sendfile on; # 启用高效文件传输,适合静态文件 tcp_nopush on; # 优化数据包传输,减少报文数量 tcp_nodelay on; # 禁用 Nagle 算法,降低传输延迟 types_hash_max_size 2048; # 优化 MIME 类型哈希表大小 server_tokens off; # 隐藏 Nginx 版本信息,增强安全性 server_names_hash_bucket_size 64; # 域名哈希桶大小,支持长域名解析 # MIME 类型定义 include /etc/nginx/mime.types; # 引入标准 MIME 类型配置 default_type application/octet-stream; # 默认文件类型为二进制流 # SSL/TLS 安全优化 ssl_protocols TLSv1.2 TLSv1.3; # 启用安全协议,优先 TLS 1.3 ssl_prefer_server_ciphers on; # 优先使用服务器指定的加密套件 ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; # 高安全加密套件 ssl_session_timeout 1d; # SSL 会话缓存有效期,减少握手开销 ssl_session_cache shared:SSL:10m; # 共享 SSL 会话缓存,适配中型流量 ssl_session_tickets off; # 禁用会话票据,增强安全性 ssl_stapling on; # 启用 OCSP 装订,加速证书验证 ssl_stapling_verify on; # 验证 OCSP 响应,确保安全 resolver 8.8.8.8 8.8.4.4 valid=300s; # 指定 DNS 服务器,用于 OCSP 查询 resolver_timeout 5s; # 设置 DNS 解析超时时间 # 日志记录配置 log_format main # 定义标准日志格式,记录请求详情 '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main buffer=32k flush=5s; # 访问日志,优化写入性能 # Gzip 压缩优化 gzip on; # 启用内容压缩,减少传输数据量 gzip_vary on; # 添加 Vary 头,适配代理缓存 gzip_proxied any; # 对所有代理请求启用压缩 gzip_comp_level 6; # 压缩级别 6,平衡性能与效果 gzip_buffers 16 8k; # 设置压缩缓冲区,优化内存使用 gzip_http_version 1.1; # 最低支持 HTTP 1.1 进行压缩 gzip_min_length 256; # 最小压缩文件长度,避免小文件开销 gzip_types text/plain # 定义支持压缩的文件类型 text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/x-font-ttf font/opentype image/svg+xml; # 客户端请求限制 client_max_body_size 10m; # 限制请求体大小,适配静态站点 client_body_buffer_size 128k; # 请求体缓冲区,优化上传性能 # 文件缓存优化 open_file_cache max=2000 inactive=20s; # 缓存文件句柄,加速静态文件访问 open_file_cache_valid 30s; # 文件缓存有效性检查周期 open_file_cache_min_uses 2; # 文件至少访问 2 次才缓存 open_file_cache_errors on; # 缓存错误信息,减少重复检查 # Cloudflare 真实 IP 获取 set_real_ip_from 173.245.48.0/20; # Cloudflare IP 范围,用于获取真实 IP set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 108.162.192.0/18; set_real_ip_from 190.93.240.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; set_real_ip_from 162.158.0.0/15; set_real_ip_from 104.16.0.0/13; set_real_ip_from 104.24.0.0/14; set_real_ip_from 172.64.0.0/13; set_real_ip_from 131.0.72.0/22; real_ip_header CF-Connecting-IP; # 使用 Cloudflare 传递的真实客户端 IP # 引入其他配置文件 include /etc/nginx/conf.d/*.conf; # 加载额外的配置目录 include /etc/nginx/sites-enabled/*; # 加载启用的站点配置文件 } ``` 创建一个站点配置文件: ```bash sudo vim /etc/nginx/sites-available/404-blog ``` 添加以下配置(根据需要调整): ```nginx # --- 非 www 域名 HTTP 重定向配置 --- server { listen 80; # 监听 HTTP 80 端口 server_name 404blog.org; # 匹配非 www 域名 access_log /var/log/nginx/404blog_redirect_access.log main buffer=16k; # 访问日志记录,设置缓冲 error_log /var/log/nginx/404blog_redirect_error.log warn; # 错误日志记录,警告级别 return 301 https://www.404blog.org$request_uri; # 永久重定向到 HTTPS 的 www 域名 } # --- 非 www 域名 HTTPS 重定向配置 --- server { listen 443 ssl; # 监听 HTTPS 443 端口并启用 SSL http2 on; # 启用 HTTP/2 协议,提升性能 server_name 404blog.org; # 匹配非 www 域名 include /etc/nginx/snippets/ssl-404blog.conf; # 引入预配置的 SSL 设置 access_log /var/log/nginx/404blog_ssl_redirect_access.log main buffer=16k; # 访问日志记录 error_log /var/log/nginx/404blog_ssl_redirect_error.log warn; # 错误日志记录 return 301 https://www.404blog.org$request_uri; # 永久重定向到 HTTPS 的 www 域名 } # --- 主域名 www 的 HTTP 重定向配置 --- server { listen 80; # 监听 HTTP 80 端口 server_name www.404blog.org; # 匹配 www 域名 access_log /var/log/nginx/404blog_www_http_access.log main buffer=16k; # 访问日志记录 error_log /var/log/nginx/404blog_www_http_error.log warn; # 错误日志记录 return 301 https://$host$request_uri; # 重定向到 HTTPS,保留主机名和路径 } # --- 主域名 www 的 HTTPS 服务配置 --- server { listen 443 ssl; # 监听 HTTPS 443 端口并启用 SSL http2 on; # 启用 HTTP/2 协议,加速传输 server_name www.404blog.org; # 匹配 www 域名 include /etc/nginx/snippets/ssl-404blog.conf; # 引入 SSL 相关配置片段 access_log /var/log/nginx/404blog_www_https_access.log main buffer=32k flush=5s; # 访问日志,设置更大缓冲和刷新时间 error_log /var/log/nginx/404blog_www_https_error.log warn; # 错误日志记录 # 安全相关的 HTTP 响应头配置 add_header X-Content-Type-Options "nosniff" always; # 防止浏览器嗅探 MIME 类型 add_header X-Frame-Options "DENY" always; # 禁止页面被嵌入到 iframe 中 add_header X-XSS-Protection "1; mode=block" always; # 启用 XSS 防护机制 add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 限制跨域时的 Referrer 信息 add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https:; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' https://cdn.jsdelivr.net; connect-src 'self'; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self';" always; # CSP 策略,增强安全性 add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # HSTS 强制 HTTPS 连接 add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; # 限制浏览器敏感权限 root /var/www/404-blog; # 设置网站根目录,指向静态文件 index index.html; # 默认首页文件 if ($request_method !~ ^(GET|HEAD)$) { # 限制请求方法,仅允许 GET 和 HEAD return 405; # 其他方法一律返回 405 错误 } # 基本路由配置 location / { try_files $uri $uri/ =404; # 尝试匹配文件或目录,无匹配则返回 404 } # 特殊文件(如 robots.txt 和 favicon.ico)的处理 location ~ ^/(robots\.txt|favicon\.ico)$ { access_log off; # 关闭访问日志,减少磁盘 I/O log_not_found off; # 关闭未找到文件的日志记录 expires 30d; # 设置 30 天缓存过期时间 add_header Cache-Control "public, immutable"; # 设置公开且不可变缓存 } # RSS 和 Sitemap 文件缓存策略 location ~* \.(xml|json)$ { expires 12h; # 缓存时间设为 12 小时 add_header Cache-Control "public, must-revalidate"; # 公开缓存但需验证 } # 图片等静态资源的缓存策略 location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ { expires 30d; # 图片资源缓存 30 天 add_header Cache-Control "public, immutable"; # 不可变缓存,适合 CDN access_log off; # 关闭访问日志 } # CSS 和 JS 文件缓存策略 location ~* \.(css|js)$ { expires 7d; # 缓存时间为 7 天 add_header Cache-Control "public, immutable"; # 不可变缓存 access_log off; # 关闭访问日志 } # 字体文件缓存策略 location ~* \.(woff|woff2|ttf|eot|otf)$ { expires 90d; # 字体资源缓存 90 天 add_header Cache-Control "public, immutable"; # 不可变缓存 access_log off; # 关闭访问日志 } # HTML 文件缓存策略 location ~* \.html$ { expires 1h; # HTML 文件缓存 1 小时 add_header Cache-Control "public, must-revalidate"; # 公开缓存但需验证 } # 禁止访问隐藏文件和敏感目录 location ~ /\. { deny all; # 拒绝访问以 . 开头的文件或目录 access_log off; # 关闭访问日志 log_not_found off; # 关闭未找到日志 } # 自定义错误页面配置 error_page 404 /404.html; # 404 错误页面指向自定义文件 error_page 500 502 503 504 /50x.html; # 5xx 错误页面指向自定义文件 location = /404.html { root /var/www/404-blog; # 404 页面文件所在根目录 internal; # 仅限内部访问 } location = /50x.html { root /var/www/404-blog; # 5xx 页面文件所在根目录 internal; # 仅限内部访问 } } ``` 启用站点并创建部署目录: ```bash sudo ln -s /etc/nginx/sites-available/your-blog /etc/nginx/sites-enabled/ sudo mkdir -p /var/www/your-blog sudo chown -R $USER:$USER /var/www/your-blog # 确保部署用户有权限 sudo nginx -t # 测试配置 sudo systemctl reload nginx ``` ## 3. 准备 SSH 密钥对 为了让 GitHub Actions 能够安全地连接到您的服务器,创建一个专用的 SSH 密钥: ```bash ssh-keygen -t rsa -b 4096 -C "github-actions-deploy" -f ~/.ssh/github-actions ``` 在您的服务器上,将公钥添加到 authorized_keys: ```bash cat ~/.ssh/github-actions.pub >> ~/.ssh/authorized_keys ``` ## 4. 配置 GitHub 仓库 Secrets 将私钥和其他必要信息添加到 GitHub 仓库的 Secrets 中: 1. 在 GitHub 仓库页面,点击 "Settings" → "Secrets and variables" → "Actions" → "New repository secret" 2. 添加以下 Secrets: - `SSH_PRIVATE_KEY`: 您生成的私钥内容(整个文件内容) - `SERVER_HOST`: 您服务器的 IP 地址或域名 - `SERVER_USERNAME`: SSH 登录用户名 - `SERVER_PORT`: SSH 端口(通常是 22) - `SERVER_DEPLOY_PATH`: 部署路径(如 /var/www/your-blog) ## 5. 创建 GitHub Actions 工作流 在您的 Hugo 项目中创建 `.github/workflows/deploy.yml` 文件: ```yaml name: Deploy Hugo site to Server on: push: branches: - master jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 with: submodules: true fetch-depth: 0 - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: hugo-version: "latest" extended: true - name: Build run: hugo --minify - name: Install SSH Key uses: shimataro/ssh-key-action@v2 with: key: ${{ secrets.SSH_PRIVATE_KEY }} known_hosts: "just-a-placeholder" - name: Adding Known Hosts run: ssh-keyscan -H -p ${{ secrets.SERVER_PORT }} ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts - name: Deploy with rsync run: | rsync -avz --delete -e "ssh -p ${{ secrets.SERVER_PORT }}" \ ./public/ \ ${{ secrets.SERVER_USERNAME }}@${{ secrets.SERVER_HOST }}:${{ secrets.SERVER_DEPLOY_PATH }} ``` 上述工作流在每次推送到主分支时触发,执行代码检出、Hugo 构建及静态文件部署等步骤,最终通过 `rsync` 工具将 `public` 目录同步到服务器。 # 图片管理策略 因为我这边更期望在 Obsidian 中进行编辑,所以只研究了两种图片管理方式: ## 1. 本地存储方案 此方案来源于 Hugo 论坛的 jmooring 最佳解决方案: **Obsidian 配置** ```json { "attachmentFolderPath": "attachments", "useMarkdownLinks": true, "newLinkFormat": "absolute" } ``` 对应了设置中的如下配置,我图片存储在了 images 下: ![](../../attachment/image-20260325223507125.png) **Hugo 配置** ```toml [markup.goldmark.renderHooks.image] enableDefault = true [markup.goldmark.renderHooks.link] enableDefault = true [[module.mounts]] source = 'assets' target = 'assets' [[module.mounts]] source = 'attachments' target = 'assets/attachments' ``` **目录结构** ``` attachments/ ├── documents/ │ ├── a.pdf │ └── b.pdf └── images/ ├── kitten-a.jpg └── kitten-b.jpg ``` ## 2. 图床存储方案 此时可以使用 Obsidian 的插件 Image Upload Toolkit。特别感谢作者,当我想使用此方案时,暂时还不支持 R2 上传,作者了解后,很快进行了适配。 我的配置如下: ![](../../attachment/image-20260325223528301.png) 上图重 `Attachment location` 需为 `/`,否则不适配插件会有找不到图片的异常信息。 ![](../../attachment/image-20260325224014579.png) 上图所需要的配置在 R2 配置界面均可以找到: ![](../../attachment/image-20260325224025519.png) 存储桶设置中,推荐自定义域,当然前提时你需要在 Cloud flare 进行域名托管。才可以使用子域。 ![](../../attachment/image-20260325224034041.png) # 缓存加速 本设计主要聚焦于 Ng 和 Cloudflare 的配置,操作简单,基本通过点击即可完成。重点内容通过截图展示,一目了然。如果您想深入学习更专业的使用方法,建议参考相关教程。 ## 1. Ng 加速配置 使用上述 Ng 配置已经处理好了大多数缓存配置和安全策略。 ## 2. Cloud flare 缓存 将域名托管到 Cf 后,可以新增 Cache Rules。 ![](../../attachment/image-20260325224046176.png) 具体规则如下: ![](../../attachment/image-20260325224055087.png) ![](../../attachment/image-20260325224113880.png) ## 3. SSL/TLS 加密 ![](../../attachment/image-20260325224123001.png) ![](../../attachment/image-20260325224132102.png) ![](../../attachment/image-20260325224141721.png) CloudFlare 为用户提供的源服务器证书是由 Cloudflare 签名的免费 TLS 证书,该域名证书属于泛域名证书,最长支持 15 年,主要用于源服务器和 Cloudflare 之间的流量加密。但是这个证书属于自签名证书,证书链不完整,缺少根证书。 使用如下网址下载 CloudFlare 的根证书/证书链文件,并上传到您的源 Web 服务器。请注意, CloudFlare 提供了 ECC 和 RSA 版本两个文件,具体下载哪一个参考上图,根据自己申请源服务器证书时选择的“私钥类型”来决定。 [Cloud flare 根证书下载](https://developers.cloudflare.com/ssl/origin-configuration/origin-ca/#cloudflare-origin-ca-root-certificate) [RSA 下载](https://developers.cloudflare.com/ssl/static/origin_ca_rsa_root.pem) 根证书下载上传后 Ng 需要对应的配置,我是放到了 snippets 配置片段下,进行统一的引用。