When running a single page application (SPA) served by a web server, you sometimes want to let the SPA use routing based on the path part of the URI, rather than a fragment. (In Vue.js: createWebHistory
vs. createWebHashHistory
.) If that is the case, you have to configure the web server to serve the application regardless of the requested path, or at least in all cases the requested path does not map to a file. I explored this using Nginx (or more specifically the nginxinc/nginx-unprivileged:alpine
Docker image), and here is what I found.
The original configuration file (/etc/nginx/nginx.conf) looked like this:
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
include /etc/nginx/mime.types;
default_type application/octet-stream;
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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
On the last line, it includes all configuration files from /etc/nginx/conf.d
, and in this case there was only one, default.conf
:
server {
listen 8080;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
Most lines are commented here, but there is one including location /
, and that is the one we want to modify. Therefore, create a new configuration file without the include and modify the root like this:
# Custom nginx configuration file.
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
proxy_temp_path /tmp/proxy_temp;
client_body_temp_path /tmp/client_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
include /etc/nginx/mime.types;
default_type application/octet-stream;
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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# Cannot include since we want our own server/location block.
#include /etc/nginx/conf.d/*.conf;
server {
listen 8080;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# if $uri file or $uri/ directory is not found, redirect internally to /index.html:
try_files $uri $uri/ /index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
The important line is try_files $uri $uri/ /index.html;
which results in files or directories not found redirect internally to /index.html
.
The last step is to modify the Dockerfile to copy the custom configuration file and replace the original one:
...
# Copy to runtime image
FROM nginxinc/nginx-unprivileged:alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build dist /usr/share/nginx/html