资讯详情

资讯详情

Linux服务器Docker部署Nginx+OpenJDK 8生产环境

简介本资源是一套面向Linux运维工程师、DevOps初学者及前后端部署人员的容器化Web服务快速搭建工具包聚焦Nginx静态部署与Redis高可用集群实践。资源涵盖Docker 18.06.3、OpenJDK 8、Nginx 1.18.0、Keepalived 1.4.5及Redis 2.6.2等核心组件的Linux安装包配套Docker容器化Nginx启动脚本、redissentinel一主二从部署文档、nginxkeepalived双机热备配置说明以及完整conf、yml、sh等配置与脚本文件可直接用于前端Jar包或HTML资源的生产级部署。压缩包共23个文件含8个配置文件nginx.conf、redis.conf等、4个源码压缩包.tgz/.tar.gz、2个Shell脚本start.sh、2个Word部署指南、2个YAML编排文件及日志、RDB等辅助文件整体296.26MB结构清晰、即取即用。目前已有3589人学习下载提供从环境安装、容器启停到集群容灾的全链路支撑材料。1. 在 Linux 服务器上用 Docker 快速搭起一个带 OpenJDK 8 的 Nginx 运行环境不是“装一堆包”而是构建可复现、可交付、可交接的最小生产就绪栈你有没有遇到过这样的场景运维同事甩来一句“环境跑不起来”你打开服务器一看/usr/lib/jvm/java-8-openjdk-amd64路径下空空如也nginx -v报 command not founddocker ps显示 daemon 没启动——而开发说“我本地明明能跑”。问题不在人而在交付物缺失没有明确的安装路径、版本约束、依赖顺序和启动契约。本篇讲的不是“Linux 怎么装 Docker”这种泛泛而谈的入门课而是紧扣标题里四个刚性要素——Linux 系统环境、Docker 安装包、Nginx 安装包、OpenJDK 8 镜像、容器化 Nginx 启动脚本——把它们串成一条可审计、可回滚、可批量部署的流水线。重点不是教你怎么敲apt install而是告诉你为什么必须用docker-ce而非docker.io为什么 Nginx 不该从源码编译而应走官方 Alpine 镜像为什么 OpenJDK 8 的镜像必须锁定openjdk:8-jre-slim而非latest以及那个看似简单的start-nginx.sh实际要解决信号转发、日志落盘、配置热加载三重陷阱。适合正在做中间件标准化、Java Web 服务容器化迁移、或需要向测试/交付团队提供“开箱即用环境包”的一线工程师。别再传.tar.gz压缩包了这次我们交付的是带校验、带版本锁、带启动契约的制品。2. 从零构建可复现的 Linux Docker Nginx OpenJDK 8 环境四层依赖的安装逻辑与版本锚定策略这个标题里藏着四个不可拆分的层级底层 OSLinux、容器运行时Docker、Web 服务Nginx、Java 运行时OpenJDK 8。它们不是并列关系而是严格依赖链Docker 依赖内核模块overlay2、cgroupNginx 容器依赖基础镜像Alpine 或 DebianOpenJDK 8 镜像又必须与 Nginx 容器共存于同一 Docker daemon 下。跳过任何一层的版本控制都会导致“本地能跑线上崩掉”。下面按真实交付顺序展开每一步都附带验证命令和失败兜底方案。2.1 确认 Linux 发行版与内核兼容性避开virtualization support not detected类报错根源Docker 对内核版本和模块支持有硬性要求。常见翻车点不是“装不上 Docker”而是装完systemctl start docker失败日志里反复出现failed to start because v或overlay: version magic 5.15.0-107-generic SMP mod_unload should be 5.15.0-107-generic SMP mod_unload——表面是版本不匹配实则是发行版内核未启用必要模块。我们不碰modprobe手动加载而是用发行版原生包管理器确保内核与用户态工具链对齐。提示本方案默认以 Ubuntu 22.04 LTS 或 CentOS Stream 8 为基线。若用 Rocky Linux 9 / AlmaLinux 9请跳过containerd.io单独安装步骤其已内置若用 Debian 12需额外启用backports源。验证当前系统是否满足最低要求# 检查内核版本Ubuntu 22.04 要求 ≥5.15CentOS Stream 8 要求 ≥4.18 uname -r # 检查 cgroup v2 是否启用Docker 24 强制要求 grep -q cgroup /proc/filesystems echo cgroup v1 OK || echo cgroup v2 required stat -fc %T /sys/fs/cgroup # 检查 overlay2 模块是否可用关键 lsmod | grep overlay # 若无输出说明未加载但不要手动 modprobe —— 交由包管理器处理正确做法是用发行版官方仓库安装 Docker CE而非第三方二进制包。以 Ubuntu 22.04 为例# 清理可能存在的旧版 docker.io sudo apt remove docker docker-engine docker.io containerd runc -y sudo apt autoremove -y # 添加 Docker 官方 GPG 密钥和仓库注意不是阿里云镜像源镜像源只加速 pull不解决内核兼容 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 锁定 Docker 版本避免自动升级引发 break change sudo apt update apt list -a docker-ce | head -10 # 查看可用版本选一个 LTS 版本如 24.0.7 sudo apt install docker-ce24.0.7-1~ubuntu.22.04~jammy docker-ce-cli24.0.7-1~ubuntu.22.04~jammy containerd.io -y # 启动并设开机自启 sudo systemctl enable docker sudo systemctl start docker # 验证必须看到 Docker version 24.0.7 且无 warning docker --version sudo docker run --rm hello-world参数说明docker-ce24.0.7-1~ubuntu.22.04~jammy显式指定版本号避免apt upgrade自动升级到不兼容版本containerd.io单独安装Docker CE 24 已将 containerd 作为独立组件必须同版本安装否则docker info会报containerd is not runninghello-world测试必须成功它验证了 daemon、socket 权限、cgroup 挂载三重通路。2.2 获取并校验 Nginx 官方安装包为什么不用apt install nginx标题明确要求“Nginx 安装包”意味着交付物需包含可离线部署的二进制或 deb/rpm 包。apt install nginx依赖网络源且版本不可控Ubuntu 22.04 默认是 1.18而生产常用 1.24。我们必须获取 Nginx 官方提供的.deb或.rpm并验证其完整性。以 Ubuntu 22.04 为例下载 Nginx 1.24.0LTS 版本# 创建专用目录存放安装包 mkdir -p ~/nginx-pkg cd ~/nginx-pkg # 下载官方 .deb注意不是 nginx.org 的源码包而是 packages.nginx.org 的预编译包 wget https://nginx.org/packages/mainline/ubuntu/pool/nginx/n/nginx/nginx_1.24.0-1~jammy_amd64.deb wget https://nginx.org/packages/mainline/ubuntu/NGINX-PKG-KEYS # 校验签名关键防止中间人篡改 gpg --dearmor NGINX-PKG-KEYS sudo cp /usr/share/keyrings/nginx-archive-keyring.gpg /usr/share/keyrings/ # 实际校验需导入公钥后用 gpg --verify此处省略冗长步骤交付时必须包含 .asc 签名文件 # 校验 SHA256交付包必须附带 checksum 文件 echo 3a7b8c9d... nginx_1.24.0-1~jammy_amd64.deb nginx-checksum.sha256 sha256sum -c nginx-checksum.sha256 # 安装不启动服务留待容器化统一管理 sudo dpkg -i nginx_1.24.0-1~jammy_amd64.deb # 若报依赖错误用 apt --fix-broken install 自动补全为什么这么做.deb包自带/etc/nginx/配置骨架、/usr/sbin/nginx二进制、systemdunit 文件比源码编译更轻量官方包已针对 Ubuntu 内核优化避免nginx: [emerg] mmap(MAP_ANON) failed类内存映射错误后续 Docker 容器中若需调试可直接docker run -v $(pwd):/host-nginx ubuntu:22.04 cat /host-nginx/nginx_1.24.0-1~jammy_amd64.deb验证包完整性。2.3 获取 OpenJDK 8 官方镜像拒绝FROM openjdk:8的玄学陷阱标题要求“OpenJDK 8 镜像安装包”即openjdk:8-jre-slim这类 Docker 镜像的离线 tar 包。很多人误以为docker pull openjdk:8就完事了但交付给客户或内网环境时必须提供.tar形式的镜像存档否则docker load无法执行。关键认知openjdk:8是个标签tag它背后指向不同 digest 的镜像。docker pull openjdk:8可能拉到openjdk:8-jdk-slim含 javac、openjdk:8-jre-slim仅运行时、甚至openjdk:8-jre-stretchDebian 9。我们必须锁定精确 digest。# 查询 openjdk:8-jre-slim 的最新稳定 digest截至 2024 年 Q2 docker pull --platform linux/amd64 openjdk:8-jre-slim docker inspect openjdk:8-jre-slim | grep -A 5 RepoDigests # 输出类似 # RepoDigests: [ # openjdksha256:abc123def456... # ] # 导出为离线包交付物核心 docker save openjdk:8-jre-slim -o openjdk8-jre-slim.tar # 验证导出包可被加载 docker load -i openjdk8-jre-slim.tar docker images | grep openjdk参数说明--platform linux/amd64强制指定平台避免在 Apple Silicon 机器上拉到arm64镜像导致 x86 服务器无法运行docker save生成的.tar是标准 OCI 格式可在任意 Docker 环境docker loadRepoDigests中的sha256:xxx是唯一指纹交付文档中必须记录此值用于审计一致性。2.4 构建最小化 Nginx 容器启动脚本不只是docker run而是可维护的契约标题最后要求“docker 容器的 nginx 启动脚本”。这不是一个start.sh就完事而是定义服务生命周期的契约如何优雅停止、如何捕获日志、如何挂载配置、如何健康检查。我们不写复杂 shell而是用docker-compose.ymlentrypoint.sh组合兼顾可读性与可扩展性。创建nginx-compose.ymlversion: 3.8 services: nginx: image: nginx:1.24.0-alpine container_name: prod-nginx restart: unless-stopped ports: - 80:80 - 443:443 volumes: - ./conf/nginx.conf:/etc/nginx/nginx.conf:ro - ./html:/usr/share/nginx/html:ro - ./logs:/var/log/nginx:rw healthcheck: test: [CMD, curl, -f, http://localhost:80/health] interval: 30s timeout: 10s retries: 3 start_period: 40s # 关键不使用默认的 PID 1而是用 dumb-init 代理信号 entrypoint: [/sbin/dumb-init, --]配套entrypoint.sh用于自定义初始化逻辑#!/bin/sh # entrypoint.sh —— 放在项目根目录chmod x set -e # 1. 确保日志目录存在且权限正确容器内 UID 101 为 nginx 用户 mkdir -p /var/log/nginx chown -R 101:101 /var/log/nginx # 2. 检查配置语法失败则退出避免容器启动后立即 crash nginx -t # 3. 执行原始 CMD即 nginx -g daemon off; exec $逻辑说明dumb-init解决 PID 1 信号转发问题当docker stop发送 SIGTERMdumb-init会转发给 nginx 主进程而非被僵尸进程吞掉healthcheck使用curl而非nc确保 Nginx 真正响应 HTTP而非仅端口开放entrypoint.sh中nginx -t是血泪经验配置文件语法错误会导致容器反复重启加此检查可提前暴露问题chown -R 101:101是 Alpine 镜像特有坑nginx 官方 Alpine 镜像固定使用 UID 101不手动 chown 会导致日志写入失败。3. 四类典型避坑指南从内核模块缺失到 OpenJDK 8 字节码兼容性断裂交付环境最怕的不是不会装而是装完跑几天突然崩。下面列出我在 12 个 Java Web 项目容器化迁移中踩过的真坑每一条都附带现象 → 原因 → 解决闭环不是网上抄来的泛泛而谈。3.1 现象docker: Error response from daemon: failed to create endpoint ... on network bridge: failed to add the host (veth) interface to the bridge: operation not supported.原因Linux 内核未启用CONFIG_VETH或CONFIG_BRIDGE模块常见于定制内核如某些云厂商精简版或 WSL2 环境。docker info中Kernel Version正常但Network部分显示WARNING: No swap limit support且Bridge网络无法创建。解决Ubuntu/Debiansudo apt install linux-modules-extra-$(uname -r)补全内核模块包CentOS/RHELsudo yum install kernel-modules-extraWSL2必须在 Windows 设置中启用“适用于 Linux 的 Windows 子系统”并重启且 WSL 版本 ≥ 0.67.6验证ls /lib/modules/$(uname -r)/kernel/net/ | grep veth应有输出。3.2 现象Nginx 容器启动后curl http://localhost返回502 Bad Gatewaydocker logs prod-nginx显示connect() failed (111: Connection refused) while connecting to upstream原因nginx.conf中upstream指向http://backend:8080但backend服务未启动或网络未互通。更隐蔽的情况是docker-compose.yml中network_mode: host与ports冲突导致 Nginx 绑定到127.0.0.1:80而非0.0.0.0:80。解决检查docker network inspect bridge确认容器 IP 分配在 Nginx 容器内执行ping backend和telnet backend 8080若用host网络删除ports字段改用netstat -tlnp | grep :80查看监听地址关键修复nginx.conf中listen 80;前加listen 0.0.0.0:80;显式绑定。3.3 现象Java 应用容器启动报UnsupportedClassVersionError: com/example/App has been compiled by a more recent version of the Java Runtime但java -version显示openjdk version 1.8.0_382原因OpenJDK 8 镜像存在多个变体openjdk:8-jre-slim基于 Debian 11与openjdk:8-jre-alpine基于 musl libc。后者不兼容部分 JNI 库且javac编译目标字节码版本可能高于 JRE 实际支持版本。解决统一使用openjdk:8-jre-slimDebian 基础glibc 兼容性好编译时显式指定-target 1.8 -source 1.8在Dockerfile中添加RUN java -XshowSettings:properties -version 21 | grep java.version验证实际运行时版本。3.4 现象docker load -i openjdk8-jre-slim.tar成功但docker run --rm openjdk:8-jre-slim java -version报standard_init_linux.go:228: exec user process caused: no such file or directory原因.tar文件导出时未包含完整镜像层或docker save时镜像已被docker system prune清理。更常见的是docker load后docker images显示none说明镜像未打 tag。解决docker save前先docker tag openjdk:8-jre-slim myrepo/openjdk8:1.0docker load后执行docker images | grep openjdk若为none则docker tag $(docker images -q --filter danglingtrue) openjdk:8-jre-slim最佳实践交付包中必须包含load.sh脚本内容为docker load -i openjdk8-jre-slim.tar docker tag $(cat openjdk8-digest.txt) openjdk:8-jre-slim。3.5 现象Nginx 日志文件access.log权限为root:root且不断增长logrotate无法切割原因docker run时未指定--userNginx 主进程以 root 启动日志文件由 root 创建。Alpine 镜像中 nginx 用户 UID 为 101但挂载卷的宿主机目录属主是ubuntu:ubuntuUID 1000导致权限冲突。解决在docker-compose.yml中添加user: 101:101宿主机创建日志目录时sudo chown 101:101 ./logs或在entrypoint.sh中chown -R 101:101 /var/log/nginx见 2.4 节验证docker exec prod-nginx ls -l /var/log/nginx应显示drwxr-xr-x 1 nginx nginx。4. 启动脚本的进阶设计让start-nginx.sh支持灰度发布、配置热更新与故障自愈标题里的“nginx 启动脚本”绝不是docker-compose up -d的简单封装。真正的生产级脚本要解决三个现实问题如何在不中断服务的前提下更新 Nginx 配置如何让新配置生效时自动 reload 而非重启容器当上游 Java 服务宕机时能否自动降级返回静态页下面给出一个经过 3 个项目验证的start-nginx.sh实现。4.1 脚本结构与核心能力矩阵能力是否支持实现方式验证命令配置语法校验✅nginx -t./start-nginx.sh --dry-run配置热更新reload✅docker kill -s HUP prod-nginxcurl -I http://localhost故障降级fallback✅error_page 502 /maintenance.htmlkill -9 $(pgrep java)版本锁与校验✅sha256sum -c nginx-checksum.sha256./start-nginx.sh --verify日志轮转触发✅docker exec prod-nginx logrotate -f /etc/logrotate.d/nginxls -l ./logs/4.2 完整start-nginx.sh脚本含注释#!/bin/bash # start-nginx.sh —— 生产就绪 Nginx 启动脚本 # 用法./start-nginx.sh [--dry-run] [--verify] [--reload] set -e # 配置区所有可调参数集中在此 NGINX_CONF./conf/nginx.conf NGINX_HTML./html NGINX_LOGS./logs NGINX_IMAGEnginx:1.24.0-alpine CONTAINER_NAMEprod-nginx CHECKSUM_FILEnginx-checksum.sha256 # 函数定义 verify_checksum() { echo 正在校验 Nginx 配置包完整性... if [ ! -f $CHECKSUM_FILE ]; then echo ❌ 错误未找到 $CHECKSUM_FILE无法校验 exit 1 fi sha256sum -c $CHECKSUM_FILE 2/dev/null || { echo ❌ 校验失败$CHECKSUM_FILE 不匹配; exit 1; } echo ✅ 校验通过 } dry_run() { echo 模拟启动模式仅校验配置不启动容器 docker run --rm -v $(pwd)/$NGINX_CONF:/etc/nginx/nginx.conf:ro $NGINX_IMAGE nginx -t echo ✅ 配置语法校验通过 } reload_nginx() { echo 执行 Nginx 配置热更新... if ! docker ps | grep $CONTAINER_NAME /dev/null; then echo ❌ 容器 $CONTAINER_NAME 未运行无法 reload exit 1 fi # 向 Nginx 主进程发送 HUP 信号触发 reload docker kill -s HUP $CONTAINER_NAME echo ✅ 已发送 HUP 信号等待 2 秒... sleep 2 # 验证 reload 是否成功 if docker exec $CONTAINER_NAME nginx -t 2/dev/null; then echo ✅ reload 成功 else echo ❌ reload 失败请检查配置 exit 1 fi } start_container() { echo 启动 Nginx 容器... # 1. 确保日志目录存在 mkdir -p $NGINX_LOGS # 2. 检查配置语法关键 docker run --rm -v $(pwd)/$NGINX_CONF:/etc/nginx/nginx.conf:ro $NGINX_IMAGE nginx -t # 3. 启动容器使用 docker-compose 更可靠 if [ -f docker-compose.yml ]; then docker-compose up -d else # fallback纯 docker run docker run -d \ --name $CONTAINER_NAME \ --restart unless-stopped \ -p 80:80 -p 443:443 \ -v $(pwd)/$NGINX_CONF:/etc/nginx/nginx.conf:ro \ -v $NGINX_HTML:/usr/share/nginx/html:ro \ -v $NGINX_LOGS:/var/log/nginx:rw \ $NGINX_IMAGE fi echo ✅ 容器已启动执行健康检查... # 等待 5 秒让 Nginx 初始化 sleep 5 if curl -sf http://localhost/health /dev/null; then echo ✅ 健康检查通过 else echo ❌ 健康检查失败请检查日志docker logs $CONTAINER_NAME exit 1 fi } # 主逻辑 case $1 in --verify) verify_checksum ;; --dry-run) dry_run ;; --reload) reload_nginx ;; *) # 默认行为启动 校验 verify_checksum start_container ;; esac参数说明--verify只校验nginx-checksum.sha256用于交付前审计--dry-run用临时容器执行nginx -t不启动任何服务适合 CI/CD 流水线--reload发送HUP信号而非docker restart实现毫秒级配置更新sleep 5与curl -sf组合避免docker-compose up -d返回后 Nginx 尚未 ready 就执行健康检查。4.3 故障降级实战当 Java 服务宕机时自动返回维护页这是nginx.conf中最实用的技巧之一。在upstream块后添加upstream backend { server 172.18.0.10:8080 max_fails3 fail_timeout30s; # 当所有 server 都不可用时启用 fallback server 127.0.0.1:8080 backup; # 指向本地维护页 } server { listen 80; location / { proxy_pass http://backend; proxy_next_upstream error timeout http_500 http_502 http_503 http_504; proxy_next_upstream_tries 3; proxy_next_upstream_timeout 3s; # 关键502 错误时返回静态页 error_page 502 /maintenance.html; location /maintenance.html { root /usr/share/nginx/html; internal; } } }然后在./html/maintenance.html放入自定义维护页。当kill -9 $(pgrep java)模拟 Java 服务崩溃时Nginx 会在 3 秒内检测到502自动返回maintenance.html用户无感知。5. 验证交付物完整性的五步法从ls -la到curl -I的全链路检查清单交付不是把几个文件打包发过去就结束。真正的交付物必须通过这五步验证缺一不可。我把它做成 checklist每次打包前逐项打钩三年来零交付事故。5.1 第一步文件清单与哈希校验交付包根目录交付压缩包解压后必须包含以下文件且ls -la输出与下表一致文件名权限大小示例用途说明docker-ce_24.0.7-1~ubuntu.22.04~jammy_amd64.deb-rw-r--r--28MBDocker CE 安装包nginx_1.24.0-1~jammy_amd64.deb-rw-r--r--1.2MBNginx 官方 deb 包openjdk8-jre-slim.tar-rw-r--r--182MBOpenJDK 8 镜像离线包nginx-checksum.sha256-rw-r--r--128BNginx deb 包 SHA256 校验值start-nginx.sh-rwxr-xr-x2.1KB可执行启动脚本docker-compose.yml-rw-r--r--856B容器编排定义conf/nginx.conf-rw-r--r--1.8KBNginx 主配置文件html/index.html-rw-r--r--124B默认首页含健康检查路由注意所有.deb和.tar文件必须用sha256sum生成对应.sha256文件并在start-nginx.sh --verify中调用校验。5.2 第二步Linux 环境初始化验证在目标服务器执行# 1. 内核与模块 uname -r # 必须 ≥5.15Ubuntu或 ≥4.18CentOS lsmod | grep -E (overlay|br_netfilter) # 必须有输出 # 2. Docker daemon sudo systemctl is-active docker # 必须返回 active sudo docker info | grep -E (Server Version|Storage Driver) # 确认 overlay2 # 3. 网络连通性 sudo docker run --rm alpine ping -c 1 8.8.8.8 # 必须成功5.3 第三步Nginx 容器启动与健康检查自动化脚本编写validate.sh一键执行#!/bin/bash # validate.sh —— 全链路验证脚本 echo 步骤1加载 OpenJDK 镜像 sudo docker load -i openjdk8-jre-slim.tar sudo docker images | grep openjdk # 应显示 openjdk 8-jre-slim echo 步骤2启动 Nginx 容器 sudo ./start-nginx.sh echo 步骤3验证 HTTP 响应 if curl -sfI http://localhost | grep 200 OK /dev/null; then echo ✅ HTTP 200 响应正常 else echo ❌ HTTP 响应异常 exit 1 fi echo 步骤4验证健康检查接口 if curl -sf http://localhost/health | grep OK /dev/null; then echo ✅ /health 接口返回 OK else echo ❌ /health 接口异常 exit 1 fi echo 步骤5验证日志写入 if [ -s ./logs/access.log ]; then echo ✅ access.log 有内容写入 else echo ❌ access.log 为空 exit 1 fi echo 全链路验证通过5.4 第四步OpenJDK 8 兼容性验证Java 应用侧交付包中必须附带test-java-app.jar一个极简 Spring Boot Actuator 应用用于验证# 在容器内运行 Java 应用 sudo docker run -d \ --name test-java \ -p 8080:8080 \ -v $(pwd)/test-java-app.jar:/app.jar \ openjdk:8-jre-slim \ java -jar /app.jar # 验证端口暴露 curl -sf http://localhost:8080/actuator/health | grep UP5.5 第五步故障注入与恢复验证压测级检查这才是检验交付质量的终极考验模拟 Nginx 配置错误修改conf/nginx.conf插入listen 8080;重复端口执行./start-nginx.sh --dry-run应报nginx: [emerg] bind() to 0.0.0.0:8080 failed模拟 Java 服务宕机docker stop test-java访问http://localhost应返回maintenance.html模拟磁盘满dd if/dev/zero of./logs/fill bs1M count500观察 Nginx 是否继续写日志应自动轮转模拟网络分区sudo iptables -A OUTPUT -d 172.18.0.10 -j DROPcurl http://localhost应在 3 秒内返回502并降级模拟容器崩溃sudo docker kill prod-nginxdocker ps应在 5 秒内自动重启restart: unless-stopped生效。我坚持一个习惯每次交付前用一台全新安装的 Ubuntu 22.04 虚拟机从wget下载交付包开始全程不联网、不查文档、不问人只执行start-nginx.sh和validate.sh。如果能在 12本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →