Skip to content
huazaiki's blog
Go back

上手配置一台新的服务器(四):部署博客与 HTTPS

Edit page

前三篇完成了安全加固、终端环境配置和运行环境安装,这一篇把博客真正跑起来——拉代码、构建、挂域名、上 HTTPS。至此,这个博客从 GitHub Pages 迁到了我自己的服务器上。

拉取代码并适配

base 前缀

将 blog 仓库克隆到服务器,现在部署到自己的域名,base 设置项是将所有访问请求加上 base 前缀,访问地址变成 https://你的域名.com/<base>,检查 astro.config.ts

// astro.config.ts
export default defineConfig({
  base: "/blog",
  // ...
});

如果你希望博客直接挂在根路径 https://你的域名.com/,那把 base 改成 "/" 就行。不过我个人习惯 /blog,方便以后在根路径挂别的东西。

site.url 域名

astro-paper.config.ts 里的 SITE.url 设置成自己的域名(填根域名即可,不需要带 /blog,Astro 会自动拼接 base 路径):

// astro-paper.config.ts
site: {
  url: "https://你的域名.com",  // 改成实际域名
  // ...
}

构建

pnpm install --frozen-lockfile
pnpm build

pnpm build 做了三件事:类型检查、Astro 静态生成、Pagefind 搜索索引。完成后 dist/ 目录里就是完整的静态网站。

验证一下:

ls dist/
# index.html  posts/  tags/  search/  pagefind/  ...

注意 dist/ 里的文件就是最终网站内容,没有 /blog 子目录——/blog 只是 Astro 在 HTML 中生成资源 URL 时的路径前缀,文件系统层面不需要体现。

Nginx 站点配置

因为 base 路径是 /blog,Nginx 需要把 /blog/* 的请求指向 dist/ 目录。创建 Nginx 配置文件:

sudo vim /etc/nginx/conf.d/blog.conf
server {
    listen 80;
    server_name 你的域名.com www.你的域名.com;

    # 根路径重定向到 /blog/(暂时,等挂上更多服务再调整)
    location = / {
        return 301 /blog/;
    }

    # /blog 不带斜杠 → 301 到 /blog/
    # 这个必须放在 /blog/ 前面,不然 /blog 会被 /blog/ 拦截并 404
    location = /blog {
        return 301 /blog/;
    }

    # 博客主路径,alias 到构建产物目录
    location /blog/ {
        alias /var/www/blog/dist/;
        index index.html;
        try_files $uri $uri/ $uri.html =404;

        # 静态资源缓存(必须嵌套在 /blog/ 内,否则正则优先级更高,截走请求却找不到文件)
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    # 安全相关 header
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
}

关键点解释:

验证配置并重载:

sudo nginx -t                  # 先验证语法
sudo systemctl reload nginx

此时访问 http://你的域名.com/blog(或暂时用 IP),应该能看到博客首页。访问 http://你的域名.com 会 301 跳到 /blog

DNS 解析

在域名管理后台(阿里云 DNS / Cloudflare 等)添加 A 记录:

类型主机记录记录值
A@服务器公网 IP
Awww服务器公网 IP

生效时间取决于 TTL 设置,通常几分钟到几小时不等。用 dig 你的域名.comnslookup 查看是否已解析。

HTTPS:Let’s Encrypt + Certbot

有了域名+DNS 解析,就能申请免费 SSL 证书了。Ubuntu 下安装 certbot 及其 Nginx 插件:

sudo apt install -y certbot python3-certbot-nginx

--nginx 插件能自动读取 Nginx 配置中的 server_name,自动完成证书申请和配置:

sudo certbot --nginx -d 你的域名.com -d www.你的域名.com

过程中会问几个问题——输入邮箱(用于证书过期提醒)、同意服务条款、是否自动重定向 HTTP 到 HTTPS(选 no)

选 no 的原因:certbot 的自动重定向会把 80 端口的 server 块替换成一个纯跳转块(return 301 https://...),原有 location 配置丢失。选 no 保留我们手写的 80 端口配置,后面手动加上重定向更可控。

申请成功后,certbot 会在配置文件中追加 443 端口的 SSL server 块,但不会自动放行 443 端口。需要手动操作:

# UFW 放行 HTTPS
sudo ufw allow 443/tcp

# 阿里云安全组也要添加 443 端口入方向规则

然后手动在 80 端口的 server 块末尾加上 HTTPS 重定向——把原来博客配置底部的 80 server 块改成:

server {
    listen 80;
    server_name huazaiki.com www.huazaiki.com;
    return 301 https://$host$request_uri;
}

最终的 blog.conf 是两块 server(443 放内容、80 跳 HTTPS)。完整配置参考:

# == HTTPS server(certbot 自动生成的 443 块,手动保留内容 location)==
server {
    server_name 你的域名.com www.你的域名.com;

    location = / {
        return 301 /blog/;
    }

    location = /blog {
        return 301 /blog/;
    }

    location /blog/ {
        alias /var/www/blog/dist/;
        index index.html;
        try_files $uri $uri/ $uri.html =404;

        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }

    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/你的域名.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/你的域名.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

# == HTTP server:全部跳转 HTTPS ==
server {
    listen 80;
    server_name 你的域名.com www.你的域名.com;
    return 301 https://$host$request_uri;
}

重载配置:

sudo nginx -t && sudo systemctl reload nginx

验证一下自动续期是否正常:

sudo certbot renew --dry-run

如果输出 “Congratulations, all simulated renewals succeeded”,就没问题。certbot 默认通过 systemd timer 每天检查一次,证书到期前 30 天自动续期。

收尾

博客部署之后,日常更新文章的流程将在下一篇文章中讲述,涉及使用 Github Actions、配置 Webhook 等。


Edit page

Previous Post
上手配置一台新的服务器(五):配置日常更新工作流
Next Post
上手配置一台新的服务器(三):运行环境与 Nginx