跳过正文
  1. 系列/
  2. VPS 实战系列/

任务 6:搭建全网关架构 —— 域名解析、SSL 证书与 Docker Nginx 部署

其雁过无痕
作者
其雁过无痕
目录

📝 1. 背景与目标
#

在云服务器(VPS)上部署项目时,直接暴露端口既不安全也不优雅。本次实战的目标是:

  1. 将在 Spaceship 购买的域名 (gyqblog.top) 解析到 VPS 公网 IP。
  2. 停用并清理早期的测试项目(如 JSP 容器),释放资源。
  3. 利用 Docker 部署一个全局 Nginx 作为统一网关(反向代理)
  4. 使用 acme.sh 自动申请并部署 Let’s Encrypt 免费 SSL 证书,实现全站 HTTPS 加密。

🌐 2. DNS 解析:让域名找到服务器
#

在域名注册商(如 Spaceship)的后台,找到 Advanced DNS(高级 DNS) 设置。我们需要添加两条 A 记录(A 记录的作用是将域名直接指向一个 IPv4 地址):

  • 记录 1:主机记录 (Host) 填 @,记录值 (Value) 填 VPS 公网 IP。代表访问主域名。
  • 记录 2:主机记录 (Host) 填 www,记录值 (Value) 填 VPS 公网 IP。代表访问 www 子域名。

验证方法:在本地终端执行 ping gyqblog.top,如果返回服务器 IP,说明解析已生效。


🔐 3. SSL 证书申请与“端口保卫战”
#

3.1 安装 acme.sh 脚本
#

这是一个轻量级的自动证书申请工具:

curl https://get.acme.sh | sh -s email=你的邮箱@example.com
source ~/.bashrc

3.2 ⚠️ 避坑指南:80 端口占用问题
#

在使用 --standalone(独立模式)申请证书时,acme.sh 会临时创建一个 Web 服务来验证域名所有权,这要求服务器的 80 端口必须处于空闲状态

如果遇到报错:tcp port 80 is already used by (("docker-proxy"...)),说明之前的容器没有彻底关闭。 排查与解决:

# 1. 揪出占用端口的“内鬼”容器
docker ps

# 2. 找到占用 80 端口的 CONTAINER ID,强行停止它
docker stop <容器ID>

# 3. 再次确认端口已空出
lsof -i:80

3.3 申请并提取证书
#

端口清空后,执行申请:

acme.sh --issue -d gyqblog.top -d www.gyqblog.top --standalone

申请成功后,将证书安装到宿主机的指定目录(此目录稍后会挂载给 Nginx):

mkdir -p /opt/nginx/ssl

acme.sh --install-cert -d gyqblog.top \
--key-file       /opt/nginx/ssl/gyqblog.top.key  \
--fullchain-file /opt/nginx/ssl/gyqblog.top.pem \
--reloadcmd     "cd /root/nginx-proxy && docker compose restart nginx"

(注:--reloadcmd 保证了未来证书自动续期后,Nginx 能自动重启加载新证书。 而cd /root/nginx-proxy是存放地点,必须写明)


🏗️ 4. 核心网关搭建(Docker + Nginx)
#

为了将来的博客和 API 接口做准备,我建立一个专属的网关目录:

mkdir -p /root/nginx-proxy
cd /root/nginx-proxy

4.1 写入 Nginx 配置文件 (解决终端粘贴换行错乱)
#

踩坑记录:在某些 SSH 终端中使用 nano 右键粘贴代码时,会导致换行符丢失、格式错乱。 优雅的极客解法:使用 cat EOF 直接注入代码,绝对不会乱码。

在终端直接执行以下整段命令:

cat > nginx.conf << 'EOF'
# HTTP 强制跳转 HTTPS
server {
    listen 80;
    server_name gyqblog.top www.gyqblog.top;
    return 301 https://$host$request_uri;
}

# HTTPS 核心网关
server {
    listen 443 ssl;
    server_name gyqblog.top www.gyqblog.top;

    # 容器内的证书路径(稍后在 compose 中映射)
    ssl_certificate /etc/nginx/ssl/gyqblog.top.pem;
    ssl_certificate_key /etc/nginx/ssl/gyqblog.top.key;

    # 临时欢迎页面
    location / {
        default_type text/html;
        return 200 '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>网关成功</title></head><body><h1>网关配置成功!博客即将上线...</h1></body></html>';
    }
}
EOF

4.2 编写 docker-compose.yml
#

同样使用 cat EOF 写入容器编排配置。注意我们需要挂载配置文件和刚刚提取的 SSL 证书目录:

cat > docker-compose.yml << 'EOF'
services:
  nginx:
    image: nginx:latest
    container_name: nginx-gateway
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - /opt/nginx/ssl:/etc/nginx/ssl
EOF

4.3 启动网关
#

docker compose up -d

启动后,在浏览器访问 http://gyqblog.top,网页会自动跳转到带有安全锁的 HTTPS 页面,并显示“网关配置成功!”。


💡 5. 总结与架构演进
#

完成这一步后,服务器架构发生了质的改变: 过去是单体直连(用户直接通过 IP:端口 访问项目),现在演变成了网关代理(Nginx 独占 80 和 443 端口,处理完安全加密后,在内网安全地将请求转发给后端的真实项目)。

相关文章

番外:1G 小内存 VPS 部署 Java JSP 项目实战:Docker 本地构建 + 远程运行完美方案

在拥有了一台属于自己的 VPS(如 1核 1G内存,配置了 2G Swap)后,很多新手在尝试部署 Java 项目时,往往会选择直接在服务器上安装 Maven 或运行 docker build。但现实很残酷:Java 编译极其消耗内存,1G 的内存在构建瞬间就会被挤爆,导致系统卡死或触发 OOM (Out Of Memory) 杀掉进程。

任务 3:熟练使用终端复用工具

核心目标 # 操作:安装并学习使用 tmux。 收获:掌握在服务器上跑长耗时任务的能力。即使本地 SSH 突然断开,任务依然会在后台运行,不会前功尽弃。 核心工具:tmux # tmux (Terminal Multiplexer) 是现代服务端开发的必备工具,解决了远程连接中途掉线导致任务中断的痛点。

任务 2:分配虚拟内存 (Swap)

Linux 服务器运维笔记:分配虚拟内存 (Swap) 避坑与实操 # 0. 背景与目标 # 在小内存(如 1GB RAM)的云服务器上运行 Java、MySQL 或进行前端构建时,物理内存极易耗尽导致进程被系统杀掉(OOM)。Swap(交换空间) 充当了“虚拟内存”的角色,是服务器在高负载下的“救命支撑”。

番外:Dockerfile 常用指令详解

基础环境设置 # FROM:指定基础镜像 功能:这是每个 Dockerfile 的第一条指令(除注释外)。它决定了你的应用运行在什么环境之上。 示例:FROM ubuntu:24.04 (基于 Ubuntu 24.04 系统)或 FROM nginx:alpine (基于轻量级的 Nginx 镜像)。 WORKDIR:设置工作目录 功能:相当于 Linux 里的 cd 命令。后续的 RUN、CMD、COPY 等指令都会在这个目录下执行。如果目录不存在,Docker 会自动帮你创建。 示例:WORKDIR /app (将后续操作的默认路径设为容器内的 /app 目录)。 2. 文件复制 # COPY:复制文件/目录到容器中 功能:将宿主机(你的电脑或服务器)上的文件或目录,原封不动地拷贝到容器的指定路径下。 示例:COPY . /app (将当前宿主机目录下的所有文件,复制到容器的 /app 目录下)。 ADD:高级复制 功能:和 COPY 类似,但带有额外功能。如果复制的是一个本地的 .tar.gz 压缩包,ADD 会自动解压到目标路径;它也支持填入一个网络 URL 来下载文件。(新手推荐优先使用 COPY,语义更清晰)。 3. 执行命令与配置 # RUN:在构建镜像时执行命令 功能:这是构建阶段的主力军。通常用来安装软件包、创建文件夹、配置环境等。注意:每次 RUN 都会生成一个新的镜像层,所以通常会把多条命令用 && 连起来写。 示例:RUN apt-get update && apt-get install -y curl。 ENV:设置环境变量 功能:定义环境变量,后续的 RUN 指令可以使用,并且这些变量也会一直保留到容器运行阶段供你的程序读取。 示例:ENV MYSQL_ROOT_PASSWORD=my-secret-pw 或 ENV PORT=8080。 EXPOSE:声明监听端口 功能:这只是一个声明,告诉使用这个镜像的人,该容器内部的程序会使用哪个端口。它不会自动将端口映射到宿主机,映射依然需要在运行 docker run 时加上 -p 参数或在 docker-compose.yml 中配置。 示例:EXPOSE 80 (声明容器内的 Web 服务使用 80 端口)。 4. 容器启动指令 # CMD:容器启动时的默认命令 功能:指定容器跑起来之后要做的第一件事(例如启动 Nginx、运行 Java 后端应用等)。如果用户在 docker run 时手动指定了其他命令,CMD 的内容会被覆盖。 示例:CMD ["nginx", "-g", "daemon off;"]。 ENTRYPOINT:容器启动的主入口 功能:和 CMD 类似,但它不会被轻易覆盖。通常用于让容器表现得像一个独立的可执行程序。如果同时存在 ENTRYPOINT 和 CMD,CMD 的内容会作为参数传递给 ENTRYPOINT。 综合示例 # 为了方便理解,这里提供一个部署简单前端/静态网页的通用 Dockerfile 模板: