[{"content":"前两篇记了建站、内容组织和部署。写技术文章时很快会撞到 Markdown 的天花板：想给图片 加个标题和链接、想让代码块高亮某几行、想嵌个视频或 GitHub Gist——这些纯 Markdown 都 做不到。Hugo 的答案是 Shortcode（短代码）：在 Markdown 里写一个简单标签，构建时 由模板渲染成完整 HTML，既不用手写一坨 HTML，也不用离开 Markdown 的写作流。\n1. 内置 Shortcode：最常用的几个 Shortcode 用 {{\u0026lt; 名字 参数 \u0026gt;}} 或 {{% 名字 %}} 两种形式。区别是： 带百分号的写法 {{% ... %}} 里的内容会再走一遍 Markdown 渲染， 带尖括号的写法 {{\u0026lt; ... \u0026gt;}} 则原样输出。常用内置的有：\nShortcode 作用 figure 带标题、alt、链接的图片（比 ![]() 强） highlight 代码块，可指定语言和高亮行 gist 嵌入 GitHub Gist youtube / vimeo 嵌入视频 twitter / bilibili 嵌入社交/视频卡片 ref / relref 生成站内文章的永久链接（防链接失效） 比如用 figure 插入一张带图注和链接的图：\n{{\u0026lt; figure src=\u0026#34;hugo-server.png\u0026#34; title=\u0026#34;图 1：hugo server 实时构建\u0026#34; alt=\u0026#34;终端里 hugo server 的输出\u0026#34; caption=\u0026#34;保存即刷新，构建只要几十毫秒\u0026#34; \u0026gt;}} 它会渲染成 \u0026lt;figure\u0026gt; + \u0026lt;figcaption\u0026gt; 结构，比裸 ![]() 语义更好，主题也能统一给 图注加样式。我这几篇笔记里封面用 front matter 的 cover，正文插图大多直接用 Markdown 图片；需要图注时就换 figure。\n2. 代码高亮：Chroma 与高亮行 Hugo 内置 Chroma 语法高亮器，不需要任何 JavaScript，构建时直接把代码染成带颜色的 HTML。围栏代码块指定语言即可：\n```go package main import \u0026#34;fmt\u0026#34; func main() { fmt.Println(\u0026#34;Hello, Hugo\u0026#34;) } ``` 想高亮某几行（比如讲重点的那一行），用 highlight shortcode 加 hl_lines：\n{{\u0026lt; highlight go \u0026#34;hl_lines=5,linenos=table\u0026#34; \u0026gt;}} package main import \u0026#34;fmt\u0026#34; func main() { fmt.Println(\u0026#34;Hello, Hugo\u0026#34;) } {{\u0026lt; /highlight \u0026gt;}} 几个常用参数：\nlinenos=table：显示行号（inline 也可以，table 布局更稳）； hl_lines=3-5,8：高亮第 3 到 5 行和第 8 行； linenostart=10：行号从 10 开始（讲文件片段时有用）； style=monokai：指定配色。 配色在 hugo.toml 里全局配置，也可以关掉行号、换主题风格：\n[markup] [markup.highlight] style = \u0026#34;monokai\u0026#34; lineNos = true noClasses = false noClasses = false 时 Hugo 输出带 class 的标签，需要在模板里用内置函数 {{/highlight.GetStyles \u0026quot;monokai\u0026quot;/}} 拿到高亮 CSS 并引入页面； 嫌麻烦就保持默认，让样式内联，零配置即可用。\n3. 自定义 Shortcode：三行起步 内置的不够用时，自己写一个也非常简单——在 layouts/shortcodes/ 下放个模板文件， 文件名就是 shortcode 名。比如做一个\u0026quot;提示框\u0026quot; note：\nlayouts/shortcodes/note.html：\n\u0026lt;div class=\u0026#34;callout callout-note\u0026#34;\u0026gt; \u0026lt;strong\u0026gt;💡 {{ .Get \u0026#34;title\u0026#34; | default \u0026#34;提示\u0026#34; }}\u0026lt;/strong\u0026gt; {{ .Inner | markdownify }} \u0026lt;/div\u0026gt; 文章里这样用（注意配对的闭合标签和 .Inner）：\n{{\u0026lt; note title=\u0026#34;小坑\u0026#34; \u0026gt;}} `draft: true` 的文章默认**不会**发布，本地预览记得加 `--buildDrafts`。 {{\u0026lt; /note \u0026gt;}} 几个关键 API：\n.Get \u0026quot;name\u0026quot; / .Get 0：取命名参数或位置参数； .Inner：取标签之间的内容，配 markdownify 可让里面继续支持 Markdown； .Page、.Site：访问当前页面和站点变量。 带 .Inner 的叫成对 shortcode（有闭合标签），不带内容的是单标签（如 youtube）。理解了\u0026quot;shortcode 就是一个可传参的小模板\u0026quot;，你就能把任何重复出现的 HTML 片段（信息框、引用卡片、目录锚点、下载按钮）都抽象成 shortcode，文章里保持干净。\n小结 Shortcode 补上了 Markdown 表达能力的最后一块拼图：内置 figure/highlight 解决 九成日常需求，Chroma 让代码高亮零 JS，自定义 shortcode 让任何 HTML 片段都能被一句话 复用。 至此三篇笔记覆盖了 Hugo 的主要工作流——建站预览、内容组织与部署、模板与 shortcode 扩展。剩下的就是多写，遇到重复劳动就抽象成模板或 shortcode。\n","permalink":"https://blog.gs-lab.ac.cn/posts/hugo-shortcodes/","summary":"纯 Markdown 写文章够用，但偶尔想插入带标题的图片、高亮某几行代码、嵌一段视频时就力不从心。Hugo 的 Shortcode 就是为此而生——在 Markdown 里用一个短标签调用模板，构建时渲染成完整 HTML。这篇记录内置 shortcode、代码高亮和自定义 shortcode 的用法。","title":"Hugo 学习笔记（三）：Shortcode 与代码高亮，让 Markdown 长出 HTML"},{"content":"上篇记了从零到本地预览的流程。这篇解决三个真正开始写站之后绕不开的问题：图片怎么 跟文章放在一起、主题模板想微调该改哪、以及怎么把站点发到自己的服务器上。\n1. 用 Page Bundle 管理一篇文章的所有资源 Hugo 里一篇文章有两种放法。第一种是上篇那种单个文件 content/posts/hello.md；当文章 需要带图片、附件时，更推荐用 Page Bundle（页面包）：把文章改成一个目录，里面放 index.md 和它用到的所有资源。\ncontent/posts/ └── my-post/ ├── index.md # 文章正文（文件名必须是 index.md） ├── cover.png # 封面 └── images/ └── shot.png # 正文插图 这样做的好处是：图片和文章是一个整体。正文里直接用相对路径引用即可，Hugo 会自动 找到同目录资源并处理：\n![截图说明](images/shot.png) 封面则写在 front matter 里，PaperMod 主题会把它渲染成文章头图，还会自动生成多尺寸 响应式图片：\ncover: image: \u0026#34;cover.png\u0026#34; alt: \u0026#34;封面说明\u0026#34; caption: \u0026#34;图注文字\u0026#34; 小坑：Bundle 目录里正文文件必须叫 index.md（叶子 Bundle）。图片放在 Bundle 内， 既能被 Markdown 相对路径引用，也能被 cover.image 匹配到。\n2. 模板查找顺序：改主题，别动主题 直接去 themes/PaperMod/ 里改模板是下策——下次 git submodule update 升级主题就被 覆盖了。Hugo 的做法是在站点根目录的同名路径放一个文件去覆盖。\n查找规则简单说就是：站点自己的 layouts/ 优先，找不到才去 themes/\u0026lt;主题\u0026gt;/layouts/。 所以想改页脚，不用动主题，只要新建：\nlayouts/ └── partials/ └── footer.html # 覆盖 themes/PaperMod/layouts/partials/footer.html Hugo 渲染时会优先用你这份，主题升级也不受影响。我这个站就用这个方式加了自定义页脚 （备案信息之类）。几个最常覆盖的位置：\n想改的东西 覆盖路径（放在站点根 layouts/ 下） 页脚 partials/footer.html 页头额外代码 partials/extend_head.html 文章正文末尾 partials/extend_post_content.html 单篇文章模板 _default/single.html 3. 配置里的 taxonomy 与菜单 hugo.toml 里显式声明分类法后，tags、categories 这些页面才会按预期生成；菜单也 在这里配：\n[taxonomies] category = \u0026#34;categories\u0026#34; tag = \u0026#34;tags\u0026#34; series = \u0026#34;series\u0026#34; [menu] [[menu.main]] name = \u0026#34;文章\u0026#34; url = \u0026#34;/posts/\u0026#34; weight = 10 weight 决定菜单从左到右的顺序。改配置不需要重启，hugo server 会自动热加载。\n4. 构建：生成纯静态文件 预览没问题后，一条命令产出可部署的静态站点：\nhugo --minify 它会把所有 Markdown 渲染、套用模板、压缩 CSS/HTML，结果全部输出到 public/ 目录。 输出末尾的统计表格会告诉你生成了多少页面、处理了多少张图片——这个 public/ 就是 要上传到服务器的全部东西，里面没有任何需要服务器运行的程序。\n--minify 会压缩产物；线上构建还建议保证配置里 baseURL 填的是真实域名，否则 RSS、站点地图里的绝对链接会不对。\n5. 一键部署到自己的服务器 我的部署方式是：本地打包源码 → 上传 → 服务器上 hugo 构建 → 同步到 Nginx 根目录。 之所以在服务器上构建而不是本地构建，是为了保证环境一致，也省去本地传一大堆产物。 核心脚本长这样：\n# 1. 本地打包源码（排除 public 和主题的 .git） tar czf /tmp/blog-src.tar.gz --exclude=\u0026#39;blog/public\u0026#39; blog # 2. 上传 scp /tmp/blog-src.tar.gz ubuntu@\u0026lt;服务器\u0026gt;:/tmp/ # 3. 服务器上解包并构建 ssh ubuntu@\u0026lt;服务器\u0026gt; \u0026#34;cd ~/blog-src/blog \u0026amp;\u0026amp; hugo --minify\u0026#34; # 4. 备份旧站，再同步到 Nginx 根目录（保护证书续期目录） ssh ubuntu@\u0026lt;服务器\u0026gt; \u0026#34;sudo cp -a /var/www/blog /var/www/blog.bak.\\$(date +%Y%m%d) \u0026amp;\u0026amp; sudo rsync -a --delete --filter=\u0026#39;protect .well-known/\u0026#39; \\ ~/blog-src/blog/public/ /var/www/blog/\u0026#34; 几个我踩过、值得注意的点：\nrsync --delete 很危险也很好用：它会让目标目录和源完全一致，删掉的文章也会从 线上消失。所以我在同步前先 cp -a 备份一份旧站，出问题能秒回滚。 保护 .well-known/：acme.sh 做 HTTP-01 验证、以及证书续期都依赖 /.well-known/acme-challenge/ 这个路径。用 --filter='protect .well-known/' 让 rsync 不要删它，否则证书续期会失败（这坑我在 HTTPS 那篇 里详细记过）。 文件权限：同步后把属主改成 www-data、目录 755、文件 644，Nginx 才能正常读。 Nginx 那边就是一个最普通的静态站点配置，root 指向 /var/www/blog， try_files $uri $uri/ =404; 即可，配合上篇提到的 HTTPS 就完整了。\n小结 两篇下来，Hugo 的核心心智模型其实很清晰：content/ 里用 Markdown（和 Page Bundle） 描述内容，layouts/ 决定怎么渲染，hugo --minify 把一切烤成 public/ 里的纯静态 文件，最后随便用什么方式把 public/ 发到服务器就行。 理解了\u0026quot;内容 / 模板 / 产物\u0026quot; 这三层分离，剩下的主题定制和部署自动化都只是体力活。\n","permalink":"https://blog.gs-lab.ac.cn/posts/hugo-themes-deploy/","summary":"本地预览跑通之后，真正要面对的是：文章里的图片怎么放、主题模板想改一处该怎么办、以及怎么把生成的静态文件发到自己的服务器。这篇记录 Page Bundle、模板查找顺序和我在用的一键部署脚本。","title":"Hugo 学习笔记（二）：Page Bundle 管图片、模板查找与一键部署到服务器"},{"content":"这个小站本身就是用 Hugo 搭的。折腾下来最大的感受就是快—— 本地几百篇文章 hugo 构建一次只要几十毫秒，改一个字保存，浏览器几乎瞬间刷新。 这篇是我从零开始学 Hugo 的第一篇笔记，记录\u0026quot;装好到能在浏览器里看到自己文章\u0026quot;的完整流程。\n为什么选静态生成器 传统博客（WordPress 之类）是每次访问都让服务器查数据库、拼页面；而 Hugo 这类 静态站点生成器（SSG） 是在本地把 Markdown 提前渲染成一堆纯 HTML，上传到服务器 后由 Nginx 直接往外发。好处很实在：\n快：没有数据库、没有后端逻辑，Nginx 发静态文件能跑到网卡上限。 安全面小：服务器上没有可被注入的动态程序，漏洞少一大截。 内容即文件：文章就是 .md 文件，Git 管理、随便备份、换主机直接拷贝。 1. 安装 Hugo macOS 用 Homebrew 一行搞定（Linux/Windows 见官方安装文档）：\nbrew install hugo 注意要装 extended 版本，它支持 WebP 图片处理、Sass 编译等功能，很多主题（包括 我用的 PaperMod）会用到。装完验证一下：\nhugo version # hugo v0.165.0 ...+extended darwin/arm64 ... 2. 新建站点 一条命令生成整套目录骨架：\nhugo new site myblog 它会在当前目录建一个 myblog/，并贴心地提示接下来要做的 5 件事：装主题、改配置、 建内容、起服务。生成的目录结构是这样的：\n各目录的用途先有个印象：\n目录 作用 content/ 放文章（Markdown），博客的核心 themes/ 主题，决定长什么样 layouts/ 自己覆盖/新增的模板 assets/ 需要 Hugo 处理的资源（会被压缩、指纹） static/ 原样拷贝的静态文件（图片、favicon 等） archetypes/ 新建文章时的模板 hugo.toml 站点配置文件 3. 装一个主题 没有主题的站点是\u0026quot;裸\u0026quot;的——直接构建会警告 found no layout file，因为没有任何模板。 主题去 themes.gohugo.io 挑，我这个站用的是 PaperMod。\n推荐用 Git 子模块（submodule）安装，方便以后升级主题：\ncd myblog git init git submodule add --depth=1 \\ https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod 然后在 hugo.toml 里启用主题、顺手填上站点信息：\nbaseURL = \u0026#34;https://blog.example.com/\u0026#34; languageCode = \u0026#34;zh-cn\u0026#34; defaultContentLanguage = \u0026#34;zh-cn\u0026#34; title = \u0026#34;我的小站\u0026#34; theme = \u0026#34;PaperMod\u0026#34; 4. 写第一篇文章 用命令新建内容文件，它会按 archetypes/ 模板自动填好 front matter：\nhugo new content posts/hello.md 打开 content/posts/hello.md，开头那一段用 --- 包起来的叫 front matter（元信息）， 下面是 Markdown 正文：\n--- title: \u0026#34;你好，Hugo\u0026#34; date: 2026-08-30T10:30:00+08:00 draft: true tags: [\u0026#34;随笔\u0026#34;] --- 正文从这里开始写，**Markdown** 语法照常。 有个关键开关：draft: true 的文章默认不会发布。本地预览时要带 --buildDrafts 才能看到草稿；正式发布前记得改成 false（或删掉这行）。\n5. 本地实时预览 Hugo 内置了开发服务器，带热更新：\nhugo server --buildDrafts 看到 Web Server is available at http://localhost:1313/ 就成了。浏览器打开这个地址， 之后每次保存文件，页面会自动重新构建并刷新，终端里还能看到\u0026quot;哪篇文章被重新渲染了\u0026quot;。 这就是 Hugo 最爽的地方：改完即见，构建快到几乎无感。\n小结 到这里，一个能本地预览的 Hugo 博客就跑起来了。回顾整条链路其实就五步：\nbrew install hugo # 装 hugo new site myblog # 建站 git submodule add \u0026lt;主题\u0026gt; # 装主题 hugo new content posts/x.md # 写文章 hugo server --buildDrafts # 预览 下一篇我会接着记：内容怎么组织（Page Bundle 与图片）、模板查找规则、以及怎么把本地 构建好的静态文件部署到自己的服务器上。\n","permalink":"https://blog.gs-lab.ac.cn/posts/hugo-quickstart/","summary":"Hugo 是用 Go 写的静态站点生成器，快到构建一个站只要几十毫秒。这篇记录从安装、新建站点、装主题、写第一篇文章到本地预览的完整流程，每一步都附真实命令输出。","title":"Hugo 学习笔记（一）：从安装到本地预览，半小时搭起一个静态博客"},{"content":"一台云服务器开机后，如果直接就把服务裸奔在公网上，用不了多久就会在日志里看到 密密麻麻的 SSH 暴力破解尝试。下面是我每次拿到新机器都会过一遍的加固清单，都是 基础项，但性价比极高。\n1. SSH：关掉密码登录 这是最重要的一条。配置好密钥登录后，禁用密码认证和 root 直接登录：\n# /etc/ssh/sshd_config.d/10-hardening.conf PasswordAuthentication no PermitRootLogin no PubkeyAuthentication yes MaxAuthTries 3 X11Forwarding no 改完用 sshd -t 校验，再 systemctl restart ssh。重启前务必保留一个已登录 的会话，新开一个终端确认密钥能登录，避免把自己锁在外面。\n2. 防火墙：默认拒绝 用 UFW 设定白名单，默认拒绝入站，只放行需要的端口：\nufw default deny incoming ufw default allow outgoing ufw allow 22/tcp # SSH ufw allow 80/tcp # HTTP（证书验证） ufw allow 443/tcp # HTTPS ufw enable 原则是：只对公网开必要的端口，管理后台、数据库这类一律绑 127.0.0.1，通过 隧道或组网访问。\n3. fail2ban：挡住暴力破解 即便禁了密码登录，也建议装上 fail2ban， 让反复尝试的 IP 自动进黑名单：\n# /etc/fail2ban/jail.d/sshd.local [sshd] enabled = true maxretry = 5 findtime = 10m bantime = 1h banaction = ufw backend = systemd 记得把自己常用的组网网段加进 ignoreip，免得把自己 ban 掉。\n4. 自动安全更新 apt install unattended-upgrades dpkg-reconfigure -plow unattended-upgrades 让安全补丁自动装，重启类更新再手动安排窗口。\n5. 几个内核网络参数 在 /etc/sysctl.d/ 下放一个加固配置，常见项包括：\nnet.ipv4.tcp_syncookies = 1 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.icmp_echo_ignore_broadcasts = 1 net.ipv4.conf.all.send_redirects = 0 kernel.randomize_va_space = 2 sysctl --system 生效。\n6. 服务暴露面自查 最后用一条命令确认\u0026quot;这台机器到底在公网上听了哪些端口\u0026quot;：\nss -tlnp 逐个核对：哪些是必须对公网开放的？哪些应该绑回环、却误绑了 0.0.0.0？ 很多\u0026quot;被入侵\u0026quot;的源头，就是某个服务默认监听了所有网卡。\n这套清单不复杂，十几分钟能做完，但能挡掉绝大多数自动化扫描和暴力破解。安全没有 银弹，不过把基础项做扎实，门槛就已经比大部分公网主机高得多了。\n","permalink":"https://blog.gs-lab.ac.cn/posts/server-hardening-checklist/","summary":"一台暴露在公网的 Linux 机器，初始化阶段做好这几件事能挡掉绝大多数自动化扫描与暴力破解。一份照着做就行的加固清单。","title":"新服务器到手先做什么：我的安全加固清单"},{"content":"给一个静态站点配上 HTTPS，本质上就三步：签发证书、配置 Nginx、设置自动续期。 这篇是我反复用过几次后整理的最小流程备忘。\n1. 先用 HTTP 起站，留好验证路径 证书签发（HTTP-01 验证）需要让签发机构能通过 http://你的域名/.well-known/ acme-challenge/ 访问到一个临时文件。所以 Nginx 里要先保证 80 端口可达，并把 这个路径指向 webroot：\nserver { listen 80; server_name example.com www.example.com; location ^~ /.well-known/acme-challenge/ { root /var/www/example; } location / { return 301 https://$host$request_uri; } } 注意：80 → 443 的跳转要把验证路径排除在外，否则签发时会被 301 带走导致验证 失败。\n2. 用 acme.sh 签发证书 我用的是 acme.sh，纯脚本、不依赖 root 守护进程：\n# 签发（ECC 证书，webroot 方式） acme.sh --issue -d example.com -w /var/www/example \\ --keylength ec-256 --server zerossl # 安装到固定路径，并配置签发后自动 reload acme.sh --install-cert -d example.com --ecc \\ --key-file /etc/nginx/ssl/example.com.key \\ --fullchain-file /etc/nginx/ssl/example.com.crt \\ --reloadcmd \u0026#34;systemctl reload nginx\u0026#34; --install-cert 这一步很关键：它会把证书复制到稳定路径，并记住 reload 命令， 之后续期时会自动执行。\n3. 配置 443 server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; add_header Strict-Transport-Security \u0026#34;max-age=31536000; includeSubDomains\u0026#34; always; root /var/www/example; index index.html; location / { try_files $uri $uri/ =404; } } 改完 nginx -t 检查语法，再 systemctl reload nginx。\n4. 自动续期 acme.sh 安装时会自动加一条 cron（或 systemd timer），每天检查一次，证书到期前 30 天左右自动续期并执行上面配置的 reload 命令。一般不用手动管，只要确认定时任 务在跑：\ncrontab -l | grep acme 踩过的坑：DNSSEC 导致 Let\u0026rsquo;s Encrypt 签发失败 这是最花时间的一个坑。我有个域名挂在开启了 DNSSEC 的后缀下，但子域没有配置对应 的 DNSKEY/DS 记录。结果 Let\u0026rsquo;s Encrypt 在做 DNS 校验时会因为 DNSSEC 链不完整 而查询超时（报错类似 DNSKEY Missing）。\n解决办法是换用不强制做该校验的签发机构，比如 ZeroSSL：上面命令里的 --server zerossl 就是为此。同一套 acme.sh 流程，换个 CA 立刻就签出来了。\n小结：遇到莫名其妙的签发超时，除了看 80 端口和防火墙，也记得排查一下域名的 DNSSEC 配置。\n","permalink":"https://blog.gs-lab.ac.cn/posts/nginx-https-acme/","summary":"HTTP 跳 HTTPS、TLS 配置、证书签发与自动续期——一套可以复用的 Nginx 静态站点上 HTTPS 的最小流程，顺便记录 DNSSEC 导致的证书签发坑。","title":"给小站配好 HTTPS：Nginx + acme.sh 自动续期备忘"},{"content":"起因 几年前我几乎所有的数字生活都托管在各大云服务上：照片在某个网盘、笔记在某个 在线文档、密码存在浏览器里。用起来确实方便，直到有一天——某个服务关停了免费 额度，某个平台改了隐私政策，某个账号因为\u0026quot;异常登录\u0026quot;被锁了三天。\n我开始意识到一件事：我并不真正拥有这些数据。它们住在别人的硬盘上，按别人 的规则存在。\n于是我试着把服务一点点搬回自己手里。这条路一般叫做 self-hosting（自托管）。\n自托管到底图什么 折腾了一段时间，我觉得对个人用户来说，自托管的价值主要有三点。\n第一，数据主权。 数据在自己的机器上，备份策略自己定，服务关停也不会丢东西。 你不再需要担心某个 SaaS 哪天宣布停止服务。\n第二，可控与可学。 每一个服务怎么跑起来、端口怎么开、证书怎么签，都是自己 亲手配置的。这个过程会逼着你把网络、Linux、容器这些基本功补扎实。\n第三，便宜。 一台入门级云服务器一个月几十块钱，能同时跑十几个服务，长期来看 比一堆订阅划算得多。\n代价也要说清楚 自托管不是银弹，它有真实的成本：\n要自己负责运维。服务挂了得自己爬起来看日志，证书过期了得自己续。 安全责任在自己。公网暴露的每一个端口，都是你要守的门。 会花掉不少业余时间。尤其在刚开始踩坑的阶段。 所以我的建议是：从一个真正需要、且相对简单的服务开始，比如先跑一个自己的 书签或笔记服务，跑顺了再慢慢加，而不是一上来就搭一整套。\n这个小站会记录什么 后面我会把这一路的配置、踩坑和心得陆续记在这里：Nginx 反代、HTTPS 证书自动续期、 Docker 部署、异地组网、系统安全加固等等。\n如果你也在考虑自托管，希望这些笔记能帮你少走点弯路。\n","permalink":"https://blog.gs-lab.ac.cn/posts/why-self-host/","summary":"从把照片交给云相册，到自己搭服务——记录我走上 self-hosting 这条路的原因，以及它到底解决了什么问题。","title":"为什么我开始把服务跑在自己的服务器上"},{"content":"这是什么地方 这里是 GS Lab 高山实验室，一个随手记录的技术小站。\n我是高山，平时喜欢折腾各种开源软件、自己的服务器和家庭网络。把折腾过程中的 笔记、踩坑和心得放在这里，一方面给自己留个备忘，另一方面也希望能帮到遇到同样 问题的人。\n主要写些什么 自托管（Self-hosting）：把服务跑在自己的机器上是什么体验 组网与隧道：异地设备互联、内网穿透、虚拟组网的各种方案 运维笔记：Nginx、HTTPS 证书、Docker、系统加固这些日常琐事 开源工具：好用的自托管项目推荐与配置记录 联系 如果文章里有错误，或者你有更好的做法，欢迎交流。本站使用 Hugo 生成，主题是 PaperMod。\n本站为个人学习记录，内容仅供参考。\n","permalink":"https://blog.gs-lab.ac.cn/about/","summary":"关于这个小站和站主","title":"关于"}]