部署个人博客服务器
在 Claw Cloud 购入了一台 1C1G 服务器,记录一下我部署个人博客的过程:
我的需求
- 运行此博客,并设置好 Https 证书
- 能实时检查服务器以及 Docker 运行情况
我的方案
- Astro & astro-theme-typography 博客主题&部署方案
- Docker & Docker Compose 用于安装管理各种软件
- Nginx 网页服务器
- Beszel 需要关注服务器以及 docker 的运行情况 Github Repository
- Discord Image 利用 Discord 的图床服务 Github Repository
过程中我遇到的问题
Astro & Nginx 部署
1. 网页无法显示,并出现报错信息
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.
原因分析:
-
Astro 打包输出的 JavaScript 文件: Astro 打包后的 JavaScript 文件通常是 ES Modules (
<script type="module" src="...">
)。为了正确加载这些模块,浏览器要求服务器返回的响应头包含Content-Type: application/javascript
,否则会报错。 -
默认情况下,Nginx 不知道如何映射文件扩展名到 MIME 类型: 如果没有在
nginx.conf
中加载mime.types
,Nginx 会把所有文件的 MIME 类型当作text/plain
,而不是application/javascript
。因此,浏览器无法将返回的文件识别为 JavaScript 模块,从而报错。 -
加载
mime.types
文件: 当你在nginx.conf
中使用include mime.types;
时,Nginx 知道如何为常见的文件扩展名(如.js
)设置正确的 MIME 类型(application/javascript
)。于是,浏览器就能正确加载模块脚本,问题得以解决。
解决方法:
在 nginx.conf 加载 mime.types
http {
include mime.types;
}
因为 mime.types
文件定义了文件扩展名到 MIME 类型的映射,比如:
types {
application/javascript js;
text/css css;
text/html html;
}
2. 打开任何路径,始终显示 index.html 的内容
打开 example.com/about
依旧显示 example.com
的内容
解决方法:
添加下面的代码到 nginx.conf
http {
server {
location / {
try_files $uri $uri/ /index.html;
}
}
}
原因解释:
这段代码的作用是实现单页应用(SPA)路由回退,这是许多现代前端框架(例如Astro、React、Vue等)的常见需求。
详细解释:
-
$uri
:表示Nginx会尝试匹配客户端请求的具体文件路径。- 例如,请求
/about
时,Nginx会查找/about
是否是一个实际存在的文件。
- 例如,请求
-
$uri/
:如果没有找到匹配的文件,Nginx会尝试将路径视为一个目录(在这种情况下,它会检查是否存在/about/
这样的路径)。 -
/index.html
:如果以上两种尝试都失败了,Nginx会将请求重定向到/index.html
文件。
适用场景:
- 在单页应用中,前端的路由(例如
/about
或/contact
)通常由前端的 JavaScript 代码处理,而不是由服务器返回特定的文件。 - 如果没有配置上述规则,访问
/about
时,Nginx会直接返回 404 错误,因为它没有找到对应的文件。
通过这个配置:
- 任何未知路径(例如
/about
)都会被重定向到index.html
,然后由前端代码(如 Astro 的路由逻辑)决定显示什么内容。
为什么可以解决问题?
假如未配置 try_files
:
- 请求
/about
会导致 Nginx 直接查找/about
文件或目录。 - 如果找不到对应的文件,Nginx会直接返回
404 Not Found
,而不会将请求交给前端处理。
配置了 try_files
后:
- Nginx将所有未找到的路径(除非是实际文件)都交给
/index.html
,确保前端框架接管路由逻辑。
申请 Https 证书并配置 Nginx
1. 无法将服务器本地目录的 let’s Encrypt 证书,映射到 Nginx 容器中
docker-compose up -d
启动 Nginx 容器,出现报错信息:
nginx | nginx: [emerg] cannot load certificate "/etc/nginx/certs/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/nginx/certs/fullchain.pem, r) error:10000080:BIO routines::no such file)
此时我的 docker-compose.yaml
相关配置如下:
services:
nginx:
image: nginx:latest
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # 挂载自定义的nginx配置文件
- /etc/letsencrypt/live/example.com:/etc/nginx/certs #映射主机证书目录
nginx.conf
相关配置如下:
http {
server {
# HTTP 部分:将所有请求重定向到 HTTPS
listen 80;
server_name example.com www.example.com; # 替换为你的域名
return 301 https://$host$request_uri;
}
server {
# HTTPS 部分
listen 443 ssl;
server_name example.com www.example.com; # 替换为你的域名
# 配置 HTTPS 证书路径(Let's Encrypt)
ssl_certificate /etc/nginx/certs/fullchain.pem; # 替换为证书路径
ssl_certificate_key /etc/nginx/certs/privkey.pem; # 替换为证书路径
}
}
原因分析:
Let’s Encrypt 目录的符号链接:/etc/letsencrypt/live/example.com
目录通常包含指向实际证书文件的符号链接,而不是直接存放证书文件。因此,直接在 Docker 容器中挂载这个路径会导致问题,因为符号链接可能无法正确解析。
解决方法:
直接挂载实际证书文件,nginx.conf
配置不变,修改后的 docker-compose.yaml
相关配置如下:
services:
nginx:
image: nginx:latest
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # 挂载自定义的nginx配置文件
- /etc/letsencrypt/live/example.com/fullchain.pem:/etc/nginx/certs/fullchain.pem #映射主机证书目录
- /etc/letsencrypt/live/example.com/privkey.pem:/etc/nginx/certs/privkey.pem #映射主机证书目录
其他可能由于粗心引发的问题
- Nginx 设置好了子域名,但是忘记在域名管理处添加对应的 DNS 记录
最终呈现
- 博客主页
- 服务器数据看板
- 图床服务