云计算百科
云计算领域专业知识百科平台

【Linux】搭建 Apache HTTP 服务器

在这里插入图片描述

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Linux这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


文章目录

  • 🐧 在 Linux 上搭建 Apache HTTP 服务器 —— 从零到生产环境部署
    • 💡 为什么选择 Apache?
    • 🖥️ 环境准备
      • 检查系统版本
      • 更新系统包
    • 🚀 安装 Apache HTTP Server
    • 🔍 验证安装是否成功
    • 🗂️ Apache 目录结构详解
    • ⚙️ 基础配置优化
      • 修改默认监听端口(可选)
      • 配置防火墙(UFW)
    • 🌐 配置虚拟主机(Virtual Host)
      • 创建网站目录
      • 创建测试页面
      • 创建虚拟主机配置文件
      • 启用站点并重启 Apache
    • 🔄 启用重要模块
      • 启用 rewrite 模块(用于 URL 重写)
      • 启用 SSL 模块(HTTPS 支持)
      • 启用 headers 和 expires(性能优化)
    • 📊 性能调优配置
    • 📈 使用 Mermaid 图表展示请求处理流程
    • ☕ 部署 Java Web 应用
      • 方案一:Apache + Tomcat(推荐传统项目)
        • 1. 安装 Tomcat
        • 2. 部署 WAR 包
        • 3. 配置 Apache 反向代理
      • 方案二:Apache + Spring Boot(现代微服务架构)
        • 示例 Java 代码:Spring Boot Controller
        • 启动 Spring Boot 应用
        • 配置 Apache 代理
    • 🔐 启用 HTTPS(SSL/TLS)
      • 安装 Certbot
      • 获取并安装证书
      • 自动续期
    • 🛡️ 安全加固建议
      • 1. 隐藏 Apache 版本信息
      • 2. 禁用目录浏览
      • 3. 限制 HTTP 方法
      • 4. 设置安全头
    • 📊 监控与日志分析
      • 查看实时访问日志
      • 使用 GoAccess 分析日志(推荐)
    • 🔄 自动化部署脚本示例
    • 🧪 Java 客户端测试代码
    • 📈 使用 Mermaid 展示架构拓扑
    • 🚨 故障排查技巧
      • 1. 检查 Apache 配置语法
      • 2. 查看错误日志
      • 3. 检查端口占用
      • 4. 测试本地连接
      • 5. 检查 SELinux(CentOS/RHEL)
    • 🌟 最佳实践总结
    • 📚 学习资源推荐
    • 🎯 结语
    • ❓ 常见问题解答(FAQ)
      • Q1: Apache 和 Nginx 哪个更好?
      • Q2: 如何提高 Apache 性能?
      • Q3: Apache 能直接运行 Java 吗?
      • Q4: 如何监控 Apache 性能?
      • Q5: Apache 支持 HTTP/2 吗?

🐧 在 Linux 上搭建 Apache HTTP 服务器 —— 从零到生产环境部署

Apache HTTP Server(简称 Apache)是世界上最流行的 Web 服务器软件之一。它开源、稳定、功能强大,支持模块化扩展,适用于从小型个人网站到大型企业级应用的各种场景。本文将带你从零开始在 Linux 系统上完整搭建 Apache 服务器,并结合 Java Web 应用进行实战部署。


💡 为什么选择 Apache?

在开始动手之前,我们先来了解下 Apache 的优势:

  • ✅ 成熟稳定:自1995年发布以来,Apache 已经经历了近30年的考验。
  • ✅ 高度可配置:支持 .htaccess 文件、虚拟主机、URL重写等高级功能。
  • ✅ 模块丰富:通过加载不同模块(如 mod_ssl、mod_rewrite)实现功能扩展。
  • ✅ 社区活跃:拥有庞大的开发者社区和详尽的官方文档。
  • ✅ 跨平台兼容:不仅支持 Linux,也支持 Windows、macOS 等系统。

📌 小贴士:虽然 Nginx 在静态资源处理和高并发方面表现更优,但 Apache 在动态内容处理、.htaccess 控制、与 PHP/Python 集成等方面依然具有不可替代的优势。


🖥️ 环境准备

本文以 Ubuntu 22.04 LTS 为例进行演示,其他主流发行版(如 CentOS、Debian)操作类似,仅包管理命令略有不同。

检查系统版本

lsb_release -a

输出示例:

No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.3 LTS
Release: 22.04
Codename: jammy

更新系统包

sudo apt update && sudo apt upgrade -y

确保你的系统是最新的,避免因依赖问题导致安装失败。


🚀 安装 Apache HTTP Server

Ubuntu 默认仓库中包含 Apache,我们可以直接使用 apt 安装:

sudo apt install apache2 -y

安装完成后,Apache 服务会自动启动。你可以通过以下命令检查状态:

sudo systemctl status apache2

你应该看到类似如下输出:

● apache2.service – The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2024-06-10 10:00:00 UTC; 2min ago


🔍 验证安装是否成功

打开浏览器,访问你的服务器 IP 地址或域名:

http://your-server-ip

如果看到 “Apache2 Ubuntu Default Page” 页面,说明安装成功!

你也可以在命令行中使用 curl 测试:

curl http://localhost


🗂️ Apache 目录结构详解

理解 Apache 的目录结构对后续配置至关重要:

# 主配置文件目录
/etc/apache2/

# 站点配置(启用的站点)
/etc/apache2/sites-enabled/

# 可用站点配置模板
/etc/apache2/sites-available/

# 模块配置
/etc/apache2/mods-enabled/
/etc/apache2/mods-available/

# Apache 主配置文件
/etc/apache2/apache2.conf

# 端口配置
/etc/apache2/ports.conf

# 默认网页根目录
/var/www/html/

# 日志目录
/var/log/apache2/

🧩 提示:Ubuntu 使用 a2ensite 和 a2enmod 命令来启用站点和模块,这些命令本质是在 sites-enabled 和 mods-enabled 中创建符号链接。


⚙️ 基础配置优化

修改默认监听端口(可选)

编辑 /etc/apache2/ports.conf:

sudo nano /etc/apache2/ports.conf

默认监听 80 端口:

Listen 80

如果你想改为 8080:

Listen 8080

然后重启 Apache:

sudo systemctl restart apache2

⚠️ 注意:修改端口后需确保防火墙允许新端口访问。


配置防火墙(UFW)

如果你启用了 UFW 防火墙,需要放行 HTTP 端口:

sudo ufw allow 'Apache Full'
# 或者指定端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

查看状态:

sudo ufw status


🌐 配置虚拟主机(Virtual Host)

虚拟主机允许你在同一台服务器上托管多个网站。

创建网站目录

假设我们要部署一个名为 example.com 的网站:

sudo mkdir -p /var/www/example.com/public_html
sudo chown -R $USER:$USER /var/www/example.com/public_html
sudo chmod -R 755 /var/www/example.com

创建测试页面

nano /var/www/example.com/public_html/index.html

内容如下:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to Example.com!</title>
</head>
<body>
<h1>Success! The example.com virtual host is working!</h1>
</body>
</html>

创建虚拟主机配置文件

sudo nano /etc/apache2/sites-available/example.com.conf

添加以下内容:

<VirtualHost *:80>
ServerAdmin admin@example.com
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html

ErrorLog ${APACHE_LOG_DIR}/example_error.log
CustomLog ${APACHE_LOG_DIR}/example_access.log combined

<Directory /var/www/example.com/public_html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>

启用站点并重启 Apache

sudo a2ensite example.com.conf
sudo systemctl reload apache2

✅ 提示:a2ensite 是 “Apache2 Enable Site” 的缩写。


🔄 启用重要模块

Apache 的强大之处在于其模块化架构。以下是几个常用模块:

启用 rewrite 模块(用于 URL 重写)

sudo a2enmod rewrite
sudo systemctl restart apache2

启用 SSL 模块(HTTPS 支持)

sudo a2enmod ssl
sudo systemctl restart apache2

启用 headers 和 expires(性能优化)

sudo a2enmod headers
sudo a2enmod expires
sudo systemctl restart apache2


📊 性能调优配置

编辑主配置文件:

sudo nano /etc/apache2/apache2.conf

在文件末尾添加以下优化配置:

# 启用 KeepAlive 以复用 TCP 连接
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

# MPM Prefork 配置(适用于 PHP 等非线程安全应用)
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 150
MaxConnectionsPerChild 0
</IfModule>

# 启用压缩
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
</IfModule>

# 缓存静态资源
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresDefault "access plus 2 days"
</IfModule>

重启服务使配置生效:

sudo systemctl restart apache2


📈 使用 Mermaid 图表展示请求处理流程

Apache 处理 HTTP 请求的过程可以用以下流程图表示:

#mermaid-svg-NwKKMgdcO4vUyMvd{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NwKKMgdcO4vUyMvd .error-icon{fill:#552222;}#mermaid-svg-NwKKMgdcO4vUyMvd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NwKKMgdcO4vUyMvd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NwKKMgdcO4vUyMvd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NwKKMgdcO4vUyMvd .marker.cross{stroke:#333333;}#mermaid-svg-NwKKMgdcO4vUyMvd svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NwKKMgdcO4vUyMvd p{margin:0;}#mermaid-svg-NwKKMgdcO4vUyMvd .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd .cluster-label text{fill:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd .cluster-label span{color:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd .cluster-label span p{background-color:transparent;}#mermaid-svg-NwKKMgdcO4vUyMvd .label text,#mermaid-svg-NwKKMgdcO4vUyMvd span{fill:#333;color:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd .node rect,#mermaid-svg-NwKKMgdcO4vUyMvd .node circle,#mermaid-svg-NwKKMgdcO4vUyMvd .node ellipse,#mermaid-svg-NwKKMgdcO4vUyMvd .node polygon,#mermaid-svg-NwKKMgdcO4vUyMvd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NwKKMgdcO4vUyMvd .rough-node .label text,#mermaid-svg-NwKKMgdcO4vUyMvd .node .label text,#mermaid-svg-NwKKMgdcO4vUyMvd .image-shape .label,#mermaid-svg-NwKKMgdcO4vUyMvd .icon-shape .label{text-anchor:middle;}#mermaid-svg-NwKKMgdcO4vUyMvd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NwKKMgdcO4vUyMvd .rough-node .label,#mermaid-svg-NwKKMgdcO4vUyMvd .node .label,#mermaid-svg-NwKKMgdcO4vUyMvd .image-shape .label,#mermaid-svg-NwKKMgdcO4vUyMvd .icon-shape .label{text-align:center;}#mermaid-svg-NwKKMgdcO4vUyMvd .node.clickable{cursor:pointer;}#mermaid-svg-NwKKMgdcO4vUyMvd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NwKKMgdcO4vUyMvd .arrowheadPath{fill:#333333;}#mermaid-svg-NwKKMgdcO4vUyMvd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NwKKMgdcO4vUyMvd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NwKKMgdcO4vUyMvd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NwKKMgdcO4vUyMvd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NwKKMgdcO4vUyMvd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NwKKMgdcO4vUyMvd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NwKKMgdcO4vUyMvd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NwKKMgdcO4vUyMvd .cluster text{fill:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd .cluster span{color:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NwKKMgdcO4vUyMvd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NwKKMgdcO4vUyMvd rect.text{fill:none;stroke-width:0;}#mermaid-svg-NwKKMgdcO4vUyMvd .icon-shape,#mermaid-svg-NwKKMgdcO4vUyMvd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NwKKMgdcO4vUyMvd .icon-shape p,#mermaid-svg-NwKKMgdcO4vUyMvd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NwKKMgdcO4vUyMvd .icon-shape .label rect,#mermaid-svg-NwKKMgdcO4vUyMvd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NwKKMgdcO4vUyMvd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NwKKMgdcO4vUyMvd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NwKKMgdcO4vUyMvd :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

客户端发起 HTTP 请求

DNS 解析

请求到达 Apache 服务器

匹配 VirtualHost

检查 .htaccess 规则

执行 URL 重写

请求的是静态文件?

直接返回文件

转发给后端处理器如 PHP, Tomcat, Python

生成动态内容

Apache 返回响应

客户端渲染页面

这个流程图展示了 Apache 如何接收请求、匹配虚拟主机、应用重写规则,最后返回响应的全过程。


☕ 部署 Java Web 应用

虽然 Apache 本身不直接运行 Java 应用,但我们可以通过反向代理的方式,将请求转发给后端的 Tomcat 或 Spring Boot 应用。

方案一:Apache + Tomcat(推荐传统项目)

1. 安装 Tomcat

sudo apt install tomcat9 tomcat9-admin -y
sudo systemctl start tomcat9
sudo systemctl enable tomcat9

2. 部署 WAR 包

将你的 Java Web 应用打包为 .war 文件,放入:

sudo cp your-app.war /var/lib/tomcat9/webapps/

Tomcat 会自动解压并部署。

3. 配置 Apache 反向代理

启用 proxy 模块:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo systemctl restart apache2

编辑虚拟主机配置:

sudo nano /etc/apache2/sites-available/java-app.conf

<VirtualHost *:80>
ServerName javaapp.yourdomain.com
ProxyPreserveHost On
ProxyPass / http://localhost:8080/your-app/
ProxyPassReverse / http://localhost:8080/your-app/

ErrorLog ${APACHE_LOG_DIR}/javaapp_error.log
CustomLog ${APACHE_LOG_DIR}/javaapp_access.log combined
</VirtualHost>

启用站点:

sudo a2ensite java-app.conf
sudo systemctl reload apache2

现在访问 http://javaapp.yourdomain.com 就能看到你的 Java 应用了!


方案二:Apache + Spring Boot(现代微服务架构)

Spring Boot 内嵌 Tomcat,可独立运行。我们只需配置 Apache 作为前端代理。

示例 Java 代码:Spring Boot Controller

// 📄 DemoController.java
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

@GetMapping("/api/hello")
public ApiResponse hello() {
return new ApiResponse("Hello from Spring Boot via Apache!", System.currentTimeMillis());
}

@GetMapping("/health")
public HealthCheck health() {
return new HealthCheck(true, "UP", "All systems operational");
}
}

// 📄 ApiResponse.java
package com.example.demo.model;

public class ApiResponse {
private String message;
private long timestamp;

public ApiResponse(String message, long timestamp) {
this.message = message;
this.timestamp = timestamp;
}

// Getters and Setters
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public long getTimestamp() { return timestamp; }
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
}

// 📄 HealthCheck.java
package com.example.demo.model;

public class HealthCheck {
private boolean success;
private String status;
private String details;

public HealthCheck(boolean success, String status, String details) {
this.success = success;
this.status = status;
this.details = details;
}

// Getters and Setters
public boolean isSuccess() { return success; }
public void setSuccess(boolean success) { this.success = success; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getDetails() { return details; }
public void setDetails(String details) { this.details = details; }
}

启动 Spring Boot 应用

java -jar your-springboot-app.jar –server.port=8081

配置 Apache 代理

<VirtualHost *:80>
ServerName api.yourdomain.com

# 代理 API 请求
ProxyPass /api http://localhost:8081/api
ProxyPassReverse /api http://localhost:8081/api

# 代理健康检查
ProxyPass /health http://localhost:8081/health
ProxyPassReverse /health http://localhost:8081/health

# 静态资源由 Apache 直接提供(可选)
Alias /static /var/www/api.yourdomain.com/static
<Directory /var/www/api.yourdomain.com/static>
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/api_error.log
CustomLog ${APACHE_LOG_DIR}/api_access.log combined

# 启用 CORS(如需)
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type, Authorization"
</VirtualHost>

这样,Apache 负责静态资源和负载均衡,Spring Boot 专注业务逻辑,架构清晰高效。


🔐 启用 HTTPS(SSL/TLS)

安全是现代 Web 的基本要求。我们可以使用免费的 Let’s Encrypt 证书。

安装 Certbot

sudo apt install certbot python3-certbot-apache -y

获取并安装证书

sudo certbot –apache -d example.com -d www.example.com

Certbot 会自动修改 Apache 配置并重启服务。

自动续期

Let’s Encrypt 证书有效期为 90 天,设置自动续期:

sudo crontab -e

添加一行:

0 12 * * * /usr/bin/certbot renew –quiet

这将在每天中午检查并自动续期即将过期的证书。


🛡️ 安全加固建议

1. 隐藏 Apache 版本信息

编辑 /etc/apache2/conf-available/security.conf:

ServerTokens Prod
ServerSignature Off

2. 禁用目录浏览

确保所有 <Directory> 块中没有 Indexes 选项:

Options -Indexes +FollowSymLinks

3. 限制 HTTP 方法

<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>

4. 设置安全头

在虚拟主机配置中添加:

Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"


📊 监控与日志分析

查看实时访问日志

sudo tail -f /var/log/apache2/access.log

使用 GoAccess 分析日志(推荐)

安装 GoAccess:

sudo apt install goaccess -y

生成 HTML 报告:

goaccess /var/log/apache2/access.log -o report.html –log-format=COMBINED

你也可以配置定时任务自动生成日报:

# 每天凌晨 2 点生成报告
0 2 * * * goaccess /var/log/apache2/access.log -o /var/www/html/stats/report-$(date +\\%Y-\\%m-\\%d).html –log-format=COMBINED


🔄 自动化部署脚本示例

下面是一个 Bash 脚本,用于自动化部署 Java Web 应用:

#!/bin/bash
# deploy-java-app.sh

APP_NAME="my-java-app"
APP_VERSION="1.0.0"
TOMCAT_HOME="/var/lib/tomcat9"
WEBAPPS_DIR="$TOMCAT_HOME/webapps"
WAR_FILE="$APP_NAME$APP_VERSION.war"

echo "🚀 开始部署 $APP_NAME v$APP_VERSION"

# 1. 停止 Tomcat
echo "🛑 停止 Tomcat 服务…"
sudo systemctl stop tomcat9

# 2. 删除旧版本
echo "🗑️ 清理旧版本…"
sudo rm -rf "$WEBAPPS_DIR/$APP_NAME"
sudo rm -f "$WEBAPPS_DIR/$APP_NAME.war"

# 3. 复制新 WAR 包
echo "📦 部署新版本…"
sudo cp "./build/libs/$WAR_FILE" "$WEBAPPS_DIR/"

# 4. 设置权限
echo "🔐 设置权限…"
sudo chown tomcat:tomcat "$WEBAPPS_DIR/$WAR_FILE"
sudo chmod 644 "$WEBAPPS_DIR/$WAR_FILE"

# 5. 启动 Tomcat
echo "✅ 启动 Tomcat 服务…"
sudo systemctl start tomcat9

# 6. 等待部署完成
echo "⏳ 等待应用部署完成 (最多 60 秒)…"
for i in {1..12}; do
if [ -d "$WEBAPPS_DIR/$APP_NAME" ]; then
echo "🎉 应用部署成功!"
break
fi
sleep 5
done

# 7. 检查应用状态
echo "🔍 检查应用健康状态…"
sleep 10
STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/$APP_NAME/health)

if [ "$STATUS_CODE" == "200" ]; then
echo "💚 应用健康检查通过!状态码: $STATUS_CODE"
else
echo "💔 应用健康检查失败!状态码: $STATUS_CODE"
exit 1
fi

echo "✅ 部署完成!访问地址: http://your-domain.com/$APP_NAME"

保存为 deploy.sh,赋予执行权限:

chmod +x deploy.sh
./deploy.sh


🧪 Java 客户端测试代码

编写一个简单的 Java 客户端来测试部署的应用:

// 📄 ApacheIntegrationTest.java
package com.example.test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import com.google.gson.Gson;
import com.google.gson.JsonObject;

public class ApacheIntegrationTest {

private static final String BASE_URL = "http://your-domain.com/api";

public static void main(String[] args) {
ApacheIntegrationTest test = new ApacheIntegrationTest();

System.out.println("🧪 开始测试 Apache + Spring Boot 集成…");

// 测试健康检查
test.testHealthEndpoint();

// 测试 Hello 接口
test.testHelloEndpoint();

// 测试错误处理
test.testNotFoundEndpoint();

System.out.println("✅ 所有测试完成!");
}

private void testHealthEndpoint() {
System.out.println("\\n=== 测试健康检查接口 ===");
try {
String response = sendGetRequest(BASE_URL + "/health");
Gson gson = new Gson();
JsonObject json = gson.fromJson(response, JsonObject.class);

boolean success = json.get("success").getAsBoolean();
String status = json.get("status").getAsString();

if (success && "UP".equals(status)) {
System.out.println("💚 健康检查通过!状态: " + status);
System.out.println("📊 详细信息: " + json.get("details").getAsString());
} else {
System.out.println("💔 健康检查失败!状态: " + status);
}
} catch (Exception e) {
System.out.println("❌ 健康检查异常: " + e.getMessage());
}
}

private void testHelloEndpoint() {
System.out.println("\\n=== 测试 Hello 接口 ===");
try {
String response = sendGetRequest(BASE_URL + "/hello");
Gson gson = new Gson();
JsonObject json = gson.fromJson(response, JsonObject.class);

String message = json.get("message").getAsString();
long timestamp = json.get("timestamp").getAsLong();

System.out.println("💬 收到消息: " + message);
System.out.println("⏱️ 时间戳: " + timestamp);
System.out.println("✅ Hello 接口测试通过!");
} catch (Exception e) {
System.out.println("❌ Hello 接口测试失败: " + e.getMessage());
}
}

private void testNotFoundEndpoint() {
System.out.println("\\n=== 测试 404 错误处理 ===");
try {
String response = sendGetRequest(BASE_URL + "/nonexistent-endpoint");
System.out.println("⚠️ 意外成功!应该返回 404");
} catch (Exception e) {
System.out.println("✅ 正确捕获 404 错误: " + e.getMessage());
}
}

private String sendGetRequest(String urlString) throws Exception {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "Java Apache Integration Test Client");
conn.setRequestProperty("Accept", "application/json");

int responseCode = conn.getResponseCode();
System.out.println("🌐 请求 URL: " + urlString);
System.out.println("🔢 响应码: " + responseCode);

if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));

StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
in.close();

return response.toString();
} else {
throw new RuntimeException("HTTP Error: " + responseCode);
}
}
}

要运行此测试,你需要添加 Gson 依赖:

<!– pom.xml –>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>


📈 使用 Mermaid 展示架构拓扑

以下是 Apache + Java 应用的典型生产架构:

#mermaid-svg-ibduUvfQGLh3Wjwu{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ibduUvfQGLh3Wjwu .error-icon{fill:#552222;}#mermaid-svg-ibduUvfQGLh3Wjwu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ibduUvfQGLh3Wjwu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ibduUvfQGLh3Wjwu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ibduUvfQGLh3Wjwu .marker.cross{stroke:#333333;}#mermaid-svg-ibduUvfQGLh3Wjwu svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ibduUvfQGLh3Wjwu p{margin:0;}#mermaid-svg-ibduUvfQGLh3Wjwu .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu .cluster-label text{fill:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu .cluster-label span{color:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu .cluster-label span p{background-color:transparent;}#mermaid-svg-ibduUvfQGLh3Wjwu .label text,#mermaid-svg-ibduUvfQGLh3Wjwu span{fill:#333;color:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu .node rect,#mermaid-svg-ibduUvfQGLh3Wjwu .node circle,#mermaid-svg-ibduUvfQGLh3Wjwu .node ellipse,#mermaid-svg-ibduUvfQGLh3Wjwu .node polygon,#mermaid-svg-ibduUvfQGLh3Wjwu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ibduUvfQGLh3Wjwu .rough-node .label text,#mermaid-svg-ibduUvfQGLh3Wjwu .node .label text,#mermaid-svg-ibduUvfQGLh3Wjwu .image-shape .label,#mermaid-svg-ibduUvfQGLh3Wjwu .icon-shape .label{text-anchor:middle;}#mermaid-svg-ibduUvfQGLh3Wjwu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ibduUvfQGLh3Wjwu .rough-node .label,#mermaid-svg-ibduUvfQGLh3Wjwu .node .label,#mermaid-svg-ibduUvfQGLh3Wjwu .image-shape .label,#mermaid-svg-ibduUvfQGLh3Wjwu .icon-shape .label{text-align:center;}#mermaid-svg-ibduUvfQGLh3Wjwu .node.clickable{cursor:pointer;}#mermaid-svg-ibduUvfQGLh3Wjwu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ibduUvfQGLh3Wjwu .arrowheadPath{fill:#333333;}#mermaid-svg-ibduUvfQGLh3Wjwu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ibduUvfQGLh3Wjwu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ibduUvfQGLh3Wjwu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ibduUvfQGLh3Wjwu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ibduUvfQGLh3Wjwu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ibduUvfQGLh3Wjwu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ibduUvfQGLh3Wjwu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ibduUvfQGLh3Wjwu .cluster text{fill:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu .cluster span{color:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ibduUvfQGLh3Wjwu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ibduUvfQGLh3Wjwu rect.text{fill:none;stroke-width:0;}#mermaid-svg-ibduUvfQGLh3Wjwu .icon-shape,#mermaid-svg-ibduUvfQGLh3Wjwu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ibduUvfQGLh3Wjwu .icon-shape p,#mermaid-svg-ibduUvfQGLh3Wjwu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ibduUvfQGLh3Wjwu .icon-shape .label rect,#mermaid-svg-ibduUvfQGLh3Wjwu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ibduUvfQGLh3Wjwu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ibduUvfQGLh3Wjwu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ibduUvfQGLh3Wjwu :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

用户浏览器

CDNCloudflare/AWS CloudFront

负载均衡器HAProxy/Nginx

Apache Web Server 1

Apache Web Server 2

Apache Web Server N

Tomcat Instance 1

Spring Boot App 1

Tomcat Instance 2

Spring Boot App 2

Tomcat Instance N

Spring Boot App N

MySQL Database

Redis Cache

监控系统Prometheus+Grafana

这种架构提供了高可用性、负载均衡和横向扩展能力。


🚨 故障排查技巧

1. 检查 Apache 配置语法

sudo apache2ctl configtest

2. 查看错误日志

sudo tail -50 /var/log/apache2/error.log

3. 检查端口占用

sudo netstat -tlnp | grep :80

4. 测试本地连接

curl -I http://localhost

5. 检查 SELinux(CentOS/RHEL)

getenforce
# 如果是 Enforcing,可能需要调整策略
sudo setsebool -P httpd_can_network_connect 1


🌟 最佳实践总结

  • 使用虚拟主机:每个网站独立配置,便于管理和维护。
  • 启用 HTTPS:保护用户数据安全,提升 SEO 排名。
  • 定期备份配置:cp -r /etc/apache2 /backup/apache2-$(date +%Y%m%d)
  • 监控日志:设置日志轮转,避免磁盘空间耗尽。
  • 性能测试:使用 ab(Apache Bench)或 wrk 进行压力测试。
  • 安全更新:定期更新系统和 Apache 版本。

  • 📚 学习资源推荐

    想深入学习 Apache?以下资源值得收藏:

    • Apache 官方文档 — 最权威的参考资料
    • DigitalOcean Apache 教程 — 实用的分步指南
    • Mozilla Web 安全最佳实践 — 包含 Apache 安全配置建议

    🎯 结语

    通过本文,你已经掌握了在 Linux 上搭建 Apache HTTP 服务器的完整流程,包括基础安装、虚拟主机配置、性能优化、安全加固,以及与 Java Web 应用的集成部署。Apache 作为久经考验的 Web 服务器,配合现代 Java 框架,依然能够构建高性能、高可用的 Web 应用系统。

    记住,技术选型没有绝对的对错,关键是根据项目需求选择合适的工具。Apache + Java 的组合在企业级应用、内容管理系统、API 网关等场景中仍然具有强大的生命力。

    现在,轮到你动手实践了!部署你的第一个 Java Web 应用,让它运行在自己搭建的 Apache 服务器上吧!💪

    🌈 提示:技术之路永无止境,保持好奇心,持续学习,你将成为更优秀的开发者!


    ❓ 常见问题解答(FAQ)

    Q1: Apache 和 Nginx 哪个更好?

    A: 没有绝对答案。Nginx 在静态文件处理和高并发方面表现优异;Apache 在动态内容处理、.htaccess 控制、模块生态方面更强大。很多生产环境采用 Nginx 做前端 + Apache 做后端的混合架构。

    Q2: 如何提高 Apache 性能?

    A: 主要方法包括:

    • 启用压缩(mod_deflate)
    • 设置缓存头(mod_expires)
    • 使用 MPM 事件模式(mpm_event_module)
    • 启用 KeepAlive
    • 限制不必要的模块
    • 使用 CDN 加速静态资源

    Q3: Apache 能直接运行 Java 吗?

    A: 不能。Apache 是 Web 服务器,不是应用服务器。Java 应用需要运行在 Tomcat、Jetty、Undertow 等 Servlet 容器中,Apache 通过反向代理将请求转发给它们。

    Q4: 如何监控 Apache 性能?

    A: 可以使用:

    • mod_status 模块查看实时状态
    • apachetop 工具监控实时请求
    • Prometheus + Grafana 构建可视化监控
    • ELK Stack(Elasticsearch+Logstash+Kibana)分析日志

    Q5: Apache 支持 HTTP/2 吗?

    A: 支持!需要启用 mod_http2 模块,并在虚拟主机配置中添加:

    Protocols h2 http/1.1

    同时需要 HTTPS 支持,因为主流浏览器只支持 HTTP/2 over TLS。


    希望这篇详细的指南能帮助你在 Linux 上成功搭建 Apache HTTP 服务器,并顺利部署 Java Web 应用!如果有任何问题,欢迎在评论区交流讨论。Happy Coding! 🎉


    🙌 感谢你读到这里! 🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。 💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友! 💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿 🔔 关注我,不错过下一篇干货!我们下期再见!✨

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【Linux】搭建 Apache HTTP 服务器
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!