0. 背景
一个实际的应用环境中需要同时部署多个站点,所以选择同时使用nginx和apache,使用apache web容器同时部署2个站点,使用nginx进行转发。但由于网站是使用react或vue开发的,一个使用了hash router,一个使用的是history router,中途遇到一个问题是当使用的是history路由时,如果当前而在不是index页面,浏览器刷新后会出现404错误
1. 应用运行环境
操作系统:CentOS Linux release 7.6.1810 (Core)
Web容器:Apache/2.4.6 (CentOS)
nginx:nginx/1.16.0
2. Apache多站点部署快捷方法
方法一:同域名下多个站点
本质上仍是一个网站,通过二级目录的方式划分成2个不同的站点
方法二:不同域名多个站点
本质是是通过Apache的VirtualHost实现,具体配置详细说明如下:
由于在我的应用环境中向外是通过nginx做转发,所以这里说明通过VirtualHost基本端口号实现多站点的配置过程
-
在/etc/httpd/conf/httpd.conf中增加以下内容
Listen 8080 Listen 8090 #以上将在VirtualHost配置中使用 LoadModule rewrite_module modules/mod_rewrite.so #上一行配置的作用在后续解决刷新404问题中的一步
-
在/etc/httpd/conf.d/下新建host.conf文件,文件在配置以下内容
<VirtualHost localhost:8080> ServerAdmin root@localhost ServerName localhost:8091 DocumentRoot "网站A根目录" DirectoryIndex index.html <Directory "网站A根目录"> Options Indexes Includes FollowSymlinks AllowOverride All Require all granted </Directory> ErrorLog /var/log/httpd/err_8080.log LogLevel warn CustomLog /var/log/httpd/err_8080_access.log combined </VirtualHost> <VirtualHost localhost:8090> ServerAdmin root@localhost ServerName localhost:8090 DocumentRoot "网站B根目录" DirectoryIndex index.html <Directory "网站B根目录"> Options Indexes Includes FollowSymlinks AllowOverride All Require all granted </Directory> ErrorLog /var/log/httpd/err_8090.log LogLevel warn CustomLog /var/log/httpd/err_8090_access.log combined </VirtualHost>
3. nginx转发配置
这里假设A网站分配域名为a.me.com,B网站分配域名是b.me.com
详细配置如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
underscores_in_headers on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
#将http请求转发到https
server {
listen 80;
server_name a.me.com;
return 301 https://$server_name$request_uri;
}
server {
listen 80;
server_name b.me.com;
return 301 https://$server_name$request_uri;
}
# HTTPS server
#
server {
listen 443 ssl;
server_name a.me.com;
root html;
index index.html index.htm;
ssl_certificate 对应域名ssl证书路径;
ssl_certificate_key 对应域名ssl证书key路径;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location ~* / {
client_max_body_size 100M;
proxy_pass http://localhost:8080;
add_header Cache-Control 'max-age=0';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location / {
root html;
index index.html index.htm;
}
}
server {
listen 443 ssl;
server_name b.me.com;
root html;
index index.html index.htm;
ssl_certificate 对应域名ssl证书路径;
ssl_certificate_key 对应域名ssl证书key路径;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location ^~ /h5/ {
proxy_pass http://localhost:8090;
add_header Cache-Control 'max-age=0';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* / {
client_max_body_size 100M;
proxy_pass http://localhost:8090;
add_header Cache-Control 'max-age=0';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
client_max_body_size 100M;
root html;
index index.html index.htm;
}
}
}
4.怎么解决问题
在上述配置下使用React或Vue基本history的单页面路由,当当前页面不是index页面时刷新时出现404问题
-
定位产生问题原因
由于同时使用了nginx和apache,如果不确定问题是出在谁身上只能一点点的去试,显然是没办法的办法。其实从本质上分析nginx是做转发工作,那只要确定问题是不是出在转发层面就可以了。方法很直接:
由于服务并没有向外开放8080和8090端口,所以可以直接在服务上通过wget打开一个非index的具体页面,如果可以打开那么问题自然是在nginx上,否则是apache配置的问题。
经排除发现问题是在apache端
-
问题解决办法
第一步、在apache配置文件中增加以下配置
LoadModule rewrite_module modules/mod_rewrite.so
第二步、在网站根目录下新建.htaccess,文件内容如下
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule>