
简介面向Linux运维、后端开发及刚接触服务器部署的读者这套“Linux一键式安装JDK、Mysql、Redis、Nginx”资料围绕Web服务常用基础组件的自动化部署展开旨在减少逐项下载、编译、配置环境变量和处理依赖时的重复劳动。包内共27个文件以11个sh安装与启动脚本、9个gz源码/依赖压缩包为主并配有cnf、conf配置样例、rpm依赖包及tar归档压缩包约930.56MB内容涵盖JDK 8u201、MySQL 8.0.30、Redis 6.2.4与Nginx 1.20.1等版本同时纳入gcc、net-tools、libaio、perl、zlib、openssl、pcre等编译运行依赖。已有299人学习下载说明其在同类部署场景中具有一定参考价值。借助init.conf总控脚本、各组件安装脚本、systemd服务脚本、Nginx主配置、MySQL密码重置脚本等读者可梳理一键部署的脚本组织方式、组件配置入口、依赖安装顺序与服务管理思路适合用来搭建本地或测试环境并作为排错与二次改写的参考。1. 一台空机器摆在面前先想清楚“一键”到底省了哪一步一台刚交付的 Linux 测试机JDK、MySQL、Redis、Nginx 四样东西全要装谁都想一条命令跑完就收工。真上手才明白Linux 一键式安装 JDK、MySQL、Redis、Nginx 的难点从来不在敲命令而在版本组合和装完之后的收尾MySQL 8.0 默认的认证插件能把老客户端挡在门外Redis 改完 bind 忘了 protected-mode 就连不上Nginx 少编一个 ssl 模块后面上证书还得从头再来一遍。这套环境几乎是 Java 后端机器的标配装顺了一小时收工装拧了能折腾一整天最后还得删目录重来。下面按我实际落地一遍的顺序写先把版本和环境卡死再逐个组件装、配、托管成服务最后给一套能一次验证四个服务都活着的自检方法。适合手上正有一台空机器、需要把 Java 运行环境一次铺好的人。2. 落地前把环境清单定死四个组件的版本与资源占用装之前花二十分钟把版本、目录、账号定下来比装到一半改主意省事得多。一键脚本最怕的不是写错命令而是每台机器上跑出来的结果不一样——这台是 JDK 8 配 MySQL 5.7那台是 JDK 17 配 MySQL 8.0同一份脚本迟早会出问题。所以我的习惯是先把组合写进脚本头部的变量区后面所有步骤只引用变量不写死路径和版本号。2.1 版本组合表保守和激进各留一套版本不是越新越好尤其是这台机器上还要跑别人的 jar 包和旧客户端的时候。我一般准备两套组合按业务侧的实际编译目标来挑组件保守选型激进选型主要差异与影响JDK8u 系列17 LTS17 移除了 Nashorn、默认强封装 JDK 内部 API老框架反射调用容易直接报错MySQL5.78.08.0 默认caching_sha2_password、默认 utf8mb4老驱动连不上是高频问题Redis6.27.x7.x 引入了多线程 IO老客户端对 RESP3 的兼容性要提前确认Nginx1.201.24新版对部分老第三方模块的支持滞后编译前先确认模块清单挑版本的判断标准其实只有一条这台机器上跑的代码是谁编译的。业务方给的是 JDK 8 打的 war 包就别为了“新”硬上 17回头 class 版本号对不上UnsupportedClassVersionError还得回退。MySQL 同理客户端驱动版本低于 8.0 的话要么驱动跟着升级要么在 my.cnf 里显式把认证插件降级二者选一个别装作看不见。Redis 6.2 和 7.x 的差别在日常使用中几乎感知不到但 7.x 编译对 GCC 版本要求更高CentOS 7 自带的 gcc 4.8 编 7.x 会报一串 C11 相关的错这种时候要么升级编译器要么老老实实退回 6.2。Nginx 我倾向选一个编译参数能覆盖全部需求的稳定分支而不是追最新——线上换个版本重编一次风险比省下的那点性能大得多。2.2 系统基线检查四个命令排除一半的坑很多“装不上”的问题其实在装之前就已经注定了。花一分钟把这几个数打出来能省掉后面大量返工# 内存MySQL 8.0 空跑就要 400MB 上下加上 Redis 和 JVM2G 机器要谨慎 free -m # 磁盘安装目录和数据目录分开看MySQL 数据目录后期涨得最快 df -h /opt /data /var # 位数32 位机器直接放弃MySQL 8.0 根本不提供 32 位包 getconf LONG_BIT # 发行版决定后面用 yum 还是 apt别混着来 cat /etc/os-release # 端口占用3306、6379、80、8080 有没有被系统自带的旧服务占着 ss -lntp | grep -E :(3306|6379|80|8080)\sfree -m看的是 available 那一列而不是 freeLinux 会把空闲内存拿去做缓存free 小是正常的。ss -lntp这一步特别值得单独跑很多精简镜像自带 mariadb-libs 甚至一个跑着的 mariadb 实例3306 被占着MySQL 初始化完起不来日志里只有一句含糊的启动失败。时间和时区也顺手确认一下timedatectl set-timezone Asia/Shanghai timedatectl set-ntp true时间不同步在单机上顶多让日志时间对不上但一旦后面要做主从或者接口签名校验几秒的偏差就能让人查一下午。时区不对更常见——MySQL 里now()出来的时间差八小时业务侧会以为是代码问题。2.3 目录与账号规划让脚本可以重复跑第二遍一键脚本的价值有一半在于“能重跑”。要做到这点所有路径必须是幂等的目录存在就跳过用户存在就复用配置文件覆盖前先备份。我一般按下面这套结构铺# 统一的运行账号Redis 和 Nginx 用它跑不用 root groupadd -r app 2/dev/null useradd -r -g app -s /sbin/nologin app 2/dev/null # 安装目录和数据目录分离便于以后单独扩容或迁移 mkdir -p /opt/{jdk,mysql,redis,nginx} \ /data/{mysql,redis,nginx} \ /var/log/app \ /usr/local/src # 数据目录和日志目录归 app安装目录保持 root防止误改 chown -R app:app /data /var/log/app chmod 750 /data/mysql /data/redis这里有个取舍MySQL 官方建议用独立的 mysql 用户但小规模环境下统一用一个 app 账号更好管权限边界靠目录权限控制就够了。真要上生产还是把 MySQL 单独拆出去mysqld --initialize --usermysql那一步会自己建用户不需要手工加。文件描述符限制必须提前放开否则 Redis 高并发下会报Too many open filesNginx 也会在上量之后才开始报错cat /etc/security/limits.d/app.conf EOF app soft nofile 65535 app hard nofile 65535 app soft nproc 65535 app hard nproc 65535 EOF注意这个文件只对通过 PAM 登录的会话生效systemd 托管的服务读不到所以后面写 unit 文件时还要单独加一行LimitNOFILE65535两处都写才不会漏。3. 主流程上篇JDK 解包与 MySQL 静默初始化的具体参数环境铺好之后就是真正动手。这一段的顺序有讲究JDK 先装因为后面如果要用到 Java 写的管理工具MySQL 放在 Redis 和 Nginx 前面是因为它初始化最慢、最容易被别的问题干扰。每一步我都尽量写成“命令 之后要检查什么”的形式而不是一路回车到底。3.1 JDK 解包与环境变量只写三行写在 /etc/profile.dJDK 本身没什么安装过程解压、指路径、验证三步。真正容易翻车的是环境变量写在哪# --strip-components1 去掉压缩包里那层版本目录后面路径就不用带版本号 tar -zxvf jdk-8uXXX-linux-x64.tar.gz -C /opt/jdk --strip-components1 cat /etc/profile.d/jdk.sh EOF export JAVA_HOME/opt/jdk export CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH$JAVA_HOME/bin:$PATH EOF chmod x /etc/profile.d/jdk.sh source /etc/profile.d/jdk.sh java -version写在/etc/profile.d/而不是~/.bashrc是因为 systemd 启动的服务不会加载用户的 bashrc只靠.bashrc配的 JAVA_HOME在命令行里跑得好好的一旦做成服务就报JAVA_HOME not found。这个坑我踩过一次排查了半天才发现是启动上下文不同。--strip-components1也值得说一下JDK 压缩包解开后默认是jdk1.8.0_xxx/这么一层目录如果不剥掉JAVA_HOME就得写成/opt/jdk/jdk1.8.0_xxx以后升个小版本还得改所有引用它的脚本。剥掉之后/opt/jdk就是 JDK 根目录升级时只要把软链或者目录内容换掉配置一行不用动。验证别只看java -version顺手把javac -version也跑一遍javac -version 21 echo $JAVA_HOME有些精简版 JDK 包只有 JRE 没有编译器java -version正常javac找不到等到要编译点东西才发现。另外 JDK 17 之后tools.jar已经不存在了CLASSPATH 那一行可以省掉写了也不报错但没必要留着误导后人。3.2 MySQL 的 my.cnf小内存机器先改这五个参数MySQL 的配置文件决定了它能不能在这台机器上安稳跑起来。默认配置是按“你有很多内存”设计的2 核 4G 的测试机上直接照搬很容易 OOM。我一般从下面这份精简版起步[mysqld] basedir/opt/mysql datadir/data/mysql socket/data/mysql/mysql.sock port3306 userapp # 字符集8.0 默认就是 utf8mb45.7 必须显式写否则中文表情符号存不进去 character-set-serverutf8mb4 collation-serverutf8mb4_general_ci # 时区不写就是 UTC业务查出来的时间差八小时 default-time-zone08:00 # 连接数与缓冲池4G 机器给 512M 起步独占机器可以给到物理内存的 50%~60% max_connections300 innodb_buffer_pool_size512M innodb_log_file_size128M # 表名大小写8.0 只能在初始化时定装完再改会起不来 lower_case_table_names1 log-error/var/log/app/mysql-error.log slow_query_log1 long_query_time2innodb_buffer_pool_size是最值得调的一个参数它直接决定热数据能不能留在内存里。测试机上给 512M 够用给太大反而会和 Redis、JVM 抢内存导致系统开始 swap性能断崖式下跌。lower_case_table_names是另一个需要在动手前想清楚的点。很多从 Windows 迁移过来的项目SQL 里表名大小写混着写Linux 上默认区分大小写就会报表不存在。这个参数在 MySQL 8.0 里只能在初始化时指定初始化完成后再改mysqld会直接拒绝启动并提示不允许。所以要么一开始就加在 my.cnf 里要么就别动别装完再回头折腾。default-time-zone用08:00这种偏移写法最稳写Asia/Shanghai依赖系统时区表精简镜像里经常没装启动时报Unknown or incorrect time zone。3.3 初始化与改密码临时密码、socket 登录、远程授权配置写完就可以初始化数据目录了。注意这一步只跑一次跑完再去改 my.cnf 里的字符集、大小写这些就来不及了# 初始化临时密码会写进 error log不会打印在终端 /opt/mysql/bin/mysqld --defaults-file/etc/my.cnf --initialize --userapp # 从日志里捞临时密码 grep -i temporary password /var/log/app/mysql-error.log--initialize和--initialize-insecure的区别要分清楚前者生成随机临时密码后者生成空密码的 root。测试环境图省事可以用后者但初始化完必须立刻设密码否则本机任何用户都能无密码进库这是个实打实的风险点。第一次登录得用 socket 方式因为此时 root 只允许从 localhost 走 socket 连/opt/mysql/bin/mysql -uroot -p -S /data/mysql/mysql.sock进去之后三件事改 root 密码、建业务账号、按需降级认证插件ALTER USER rootlocalhost IDENTIFIED BY 换成你的强密码; -- 业务账号给到具体库别图省事给 *.* CREATE USER appuser% IDENTIFIED BY 换成你的业务密码; GRANT ALL PRIVILEGES ON appdb.* TO appuser%; FLUSH PRIVILEGES; -- 老客户端连 8.0 报 Authentication plugin caching_sha2_password cannot be loaded 时用这句 ALTER USER appuser% IDENTIFIED WITH mysql_native_password BY 换成你的业务密码;最后那句是 8.0 最经典的兼容问题。老版本的 JDBC 驱动、老版本的 Navicat 类客户端遇到caching_sha2_password直接报错很多人第一反应是换客户端其实是认证插件不匹配。要么升级驱动要么把账号降级成mysql_native_password两条路都行就是别在那儿反复试密码。远程访问打不通的时候先确认三件事的先后顺序账号的 host 是不是%、bind-address有没有限制成 127.0.0.1、防火墙有没有放行 3306。三处任意一处没配对表现都是“连接超时”但原因完全不同。4. 主流程下篇Redis 编译、Nginx 编译参数与 systemd 托管MySQL 起来之后剩下三个组件的节奏就快了。Redis 和 Nginx 都走源码编译好处是版本和模块自己说了算坏处是依赖得自己补齐编译参数漏一个后面就得重编。4.1 Redismake 之前先想好改完这四行再启动Redis 编译本身不复杂麻烦的是编译环境和启动配置cd /usr/local/src tar -zxvf redis-6.2.x.tar.gz cd redis-6.2.x # -j 按核数并行编译快很多报错先 make distclean 再重来 make -j$(nproc) make PREFIX/opt/redis install # 配置文件单独放别用源码目录里的那份 mkdir -p /opt/redis/etc cp redis.conf /opt/redis/etc/redis.confmake PREFIX/opt/redis install会把redis-server、redis-cli这些可执行文件装到/opt/redis/bin源码目录里的东西就可以留着不管了。如果编译时报jemalloc/jemalloc.h: No such file八成是之前编译残留或者缺依赖先make distclean再确认gcc、make、jemalloc-devel都装了。装完不要急着启动redis.conf里至少四行要改# 绑定内网地址而不是 0.0.0.0只给本机用就写 127.0.0.1 bind 127.0.0.1 # 和 bind 配套两个一起改才有效 protected-mode yes # 交给 systemd 托管这里必须 no否则 systemd 会以为进程退出了 daemonize no # 数据落盘目录和持久化 dir /data/redis appendonly yes appendfsync everysec # 密码和内存上限两个都要设 requirepass 换成你的强密码 maxmemory 512mb maxmemory-policy allkeys-lrubind和protected-mode必须成对考虑只改bind 0.0.0.0不改密码等于把库敞开只设密码不改 bind本地能连远程连不上会误以为是密码错了。maxmemory不设的话Redis 会一直吃内存直到把机器拖垮allkeys-lru在纯缓存场景下是合理选择如果这个 Redis 里存的是不能丢的数据那就该换成noeviction并盯着内存告警。daemonize no是配合 systemd 的关键。很多人习惯改成yes让 Redis 自己后台化结果 systemd 启动后立刻判定服务已退出systemctl status显示 failed实际上进程还在跑这种情况最容易让人怀疑人生。4.2 Nginx编译参数漏一个后面就得整台重来Nginx 的编译参数是这套环境里最值得提前想清楚的一环因为装完再补模块只能重新编译cd /usr/local/src/nginx-1.24.x ./configure \ --prefix/opt/nginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_gzip_static_module \ --with-http_realip_module \ --with-stream \ --with-pcre make -j$(nproc) make install--with-http_ssl_module默认是不编进去的等要上 HTTPS 才发现nginx -V里没有这个模块就只能重来。--with-http_realip_module在走反向代理时用来拿真实客户端 IP不加的话日志里全是上游地址排查问题时会很难受。--with-stream是四层转发做数据库或 Redis 的 TCP 代理时需要。./configure阶段报the HTTP rewrite module requires the PCRE library是缺pcre-devel报 zlib 相关的是缺zlib-devel报 SSL 相关的是缺openssl-devel。三条一起装最省事yum install -y gcc gcc-c make pcre pcre-devel zlib zlib-devel openssl openssl-devel配置文件我一般拆成主配置和站点配置两部分主配置只管全局站点配置放conf.dworker_processes auto; events { worker_connections 10240; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; include /opt/nginx/conf/conf.d/*.conf; }站点配置里最常写的是反向代理到后端 Java 服务server { listen 80; server_name _; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }worker_processes auto按 CPU 核数自动设置比手写数字靠谱。X-Forwarded-For那两行不加后端拿到的客户端 IP 永远是 127.0.0.1做限流或者审计的时候会完全失效。4.3 systemd 托管四个 unit 文件与开机自启编译安装的东西默认不带服务管理全靠手工nohup启动机器一重启就全没了。补上 unit 文件才算真正装完# /etc/systemd/system/redis.service [Unit] DescriptionRedis Afternetwork.target [Service] Userapp ExecStart/opt/redis/bin/redis-server /opt/redis/etc/redis.conf Restartalways LimitNOFILE65535 [Install] WantedBymulti-user.targetMySQL 的 unit 稍微多一点重点是ExecStart要带--defaults-file否则它会去读默认路径的配置# /etc/systemd/system/mysqld.service [Unit] DescriptionMySQL Afternetwork.target [Service] Userapp ExecStart/opt/mysql/bin/mysqld --defaults-file/etc/my.cnf Restarton-failure LimitNOFILE65535 [Install] WantedBymulti-user.targetNginx 的ExecStart用/opt/nginx/sbin/nginx -g daemon off;-g daemon off;同样是给 systemd 用的不加会以后台模式启动然后被判定为退出。四个 unit 写完之后统一重载并设开机自启systemctl daemon-reload systemctl enable --now mysqld redis nginx systemctl status mysqld redis nginx --no-pagerenable --now一次搞定开机自启和立即启动比enable完再start少一步。Restartalways和on-failure的差别在于前者无论怎么退出都拉起来后者只在非零退出码时拉。Redis 用always更稳MySQL 用on-failure避免配置写错时无限重启刷日志。5. 避坑与排查一键脚本最容易翻车的五个地方这套流程我跑过不下十遍报错信息翻来覆去就是那几条。下面五条按“现象、原因、解决”记碰到了直接对号入座。5.1 端口与网络层本机通、外面不通现象机器上curl 127.0.0.1:8080正常返回从另一台机器访问超时telnet也不通。原因多半是两层防火墙只开了一层。系统层的 firewalld 放行了云主机的安全组没放或者反过来安全组开了firewalld 还拦着。解决两边都查一遍别只看一边。firewall-cmd --list-ports firewall-cmd --permanent --add-port3306/tcp --add-port6379/tcp --add-port80/tcp firewall-cmd --reload现象MySQL 初始化成功systemctl start mysqld反复失败日志里只有一句Address already in use。原因系统自带 mariadb-libs 或者一个已经在跑的 mariadb 实例占着 3306rpm -qa | grep -i maria一看就清楚。解决卸载或者改端口。改端口更快但要记得同步改业务侧的连接串。rpm -qa | grep -i maria systemctl stop mariadb 2/dev/null sed -i s/^port3306/port3306/ /etc/my.cnf5.2 权限与安全模块配置文件对了还是 403现象Nginx 起来了访问静态文件返回 403错误日志写Permission denied但文件权限明明是 644。原因SELinux 在 enforcing 模式目录安全上下文不对。getenforce一查就是Enforcing。解决内网测试环境可以临时关掉正式环境建议改上下文而不是直接关。getenforce setenforce 0 # 临时生效重启失效 chcon -R -t httpd_sys_content_t /opt/nginx/html # 或者只改上下文现象Redis 启动报Cant open the log file或者Permission denied配置文件明明写对了。原因/data/redis属主还是 root而服务是以 app 用户跑的。编译安装的时候习惯用 root容易漏掉这一步。解决把数据目录和日志目录的属主改成运行账号一次改彻底。chown -R app:app /data/redis /var/log/app ls -ld /data/redis5.3 依赖与编译make 阶段的报错最费时间现象Redismake报jemalloc/jemalloc.h: No such file or directory。原因源码目录里有上次编译的残留或者缺jemalloc-devel。残留这种情况更常见尤其在同一目录反复折腾的时候。解决make distclean yum install -y gcc gcc-c make jemalloc-devel make -j$(nproc)现象Nginx./configure报the HTTP rewrite module requires the PCRE library或SSL modules require the OpenSSL library。原因只装了运行库没装开发包。pcre和pcre-devel是两个包前者是运行时后者才提供头文件。解决编译依赖一次性装齐别一个一个试。yum install -y pcre pcre-devel zlib zlib-devel openssl openssl-devel还有一条不在上面五条里但值得单独记MySQL 8.0 装完之后想改lower_case_table_namessystemctl restart直接失败日志提示只能在初始化时设置。这个没有后悔药只能删数据目录重来所以初始化之前一定要把 my.cnf 定稿。6. 装完怎么验证一次把四个服务都叫醒再重启一遍装完不验证等于没装。我的习惯是写一个固定的小脚本每次都跑同一套检查输出全绿才算收工。散着一条条试太容易漏尤其是 Redis 那种“启动了但没真正可用”的情况。6.1 四项连通性自检#!/bin/bash # 端口层四个服务该监听的端口都在 for p in 3306 6379 80; do ss -lntp | grep -q :$p echo PORT $p OK || echo PORT $p FAIL done # 进程层JDK 看 java其余看 systemd 状态 java -version 21 | head -1 systemctl is-active mysqld redis nginx # 应用层真正连一下比看端口靠谱 /opt/mysql/bin/mysql -h127.0.0.1 -P3306 -uappuser -p$MYSQL_PWD -e select version(); /opt/redis/bin/redis-cli -h 127.0.0.1 -a $REDIS_PWD ping curl -s -o /dev/null -w %{http_code}\n http://127.0.0.1/端口检查只能证明进程在监听证明不了能干活。MySQL 端口开着但账号密码错、Redis 端口开着但requirepass没对上这两种情况都得靠应用层那三条才能真正暴露出来。redis-cli返回PONG才算通返回NOAUTH说明密码没传对返回Connection refused才是服务没起来三种输出对应三种完全不同的处理方向。对一下预期结果检查项命令预期输出JDKjava -version版本号且与脚本里定的版本一致MySQLselect version();版本号能查出结果说明账号权限正常Redisredis-cli pingPONGNginxcurl -I 127.0.0.1200或403说明服务活着只是没首页6.2 最容易漏的一步重启一次所有服务都起来之后别急着交付。systemctl restart只能验证重启命令验证不了开机自启。真正该做的是重启整台机器然后再跑一遍上面的自检reboot # 等机器起来后重跑自检脚本四项全绿才算完成这一步能抓出两类问题一是 unit 文件里After依赖写错MySQL 比网络先起来导致启动失败二是环境变量只写在.bashrc里重启后 systemd 的服务根本读不到JAVA_HOME。这两类问题不重启永远发现不了而它们恰好会在某次机房维护之后集中爆发。从那以后我每次铺完这套环境都强制走一遍「自检脚本 真重启 再自检」的流程不给自己留“应该是好的”这种侥幸。装环境这件事能一次跑通不算本事能扛住一次重启才算。希望帮到你。本文还有配套的精品资源点击获取