Which server fallback config correctly serves Vue Router history mode routes in production?
0 reputation · 14 Apr 2025, 08:38 UTC
0 reputation · 14 Apr 2025, 08:38 UTC
Deploy a Vue 3 single‑page application that uses createWebHistory so that URLs such as /users/42 are clean and SEO friendly. The Vite dev server rewrites unknown paths to index.html, but a plain static host (nginx, Apache, CDN edge) returns a 404 on a hard‑refresh or deep link.
index.html for all SPA routes while still serving real assets and API endpoints correctly./:pathMatch(.*)*) should render a custom NotFound component instead of a blank screen.index.html for unknown SPA routes?/assets/*) from the fallback rule so that missing assets still return true 404s?index.html for a non‑existent path, or is additional client‑side logic required?35775 reputation · 14 Apr 2025, 16:29 UTC
Use the nginx directive try_files $uri $uri/ /index.html; inside a location / block.
When a request does not map to an existing file ($uri) or directory ($uri/), nginx falls back to serving /index.html. The Vue application then boots and Vue Router matches the original URL, rendering the appropriate view or the catch‑all NotFound component.
/etc/nginx/sites-available/myapp).location / block exists; replace or add:location / {
try_files $uri $uri/ /index.html;
}
Place a more specific location block for your asset folder (or common static extensions) before the catch‑all block so that requests for real files are served directly and missing assets return a genuine 404.
location /assets/ {
# optional: set expires, add_header Cache-Control, etc.
}
# Alternatively, match by extension
location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|webmanifest)$ {
# same as above
}
Because nginx processes location blocks in order of specificity, these blocks take precedence over the generic location / fallback.
Define a catch‑all route as the last entry in your router:
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/users/:id', component: UserDetail },
// … other routes
{ path: '/:pathMatch(.*)*', component: NotFound }
]
});
When nginx returns index.html for a non‑existent path, the router boots, sees the URL (e.g., /users/42) and matches the :pathMatch(.*)* pattern only if no earlier route fits, rendering the NotFound component. No extra client‑side logic is required.
sudo nginx -t && sudo systemctl reload nginx.https://example.com/users/42; you should receive a 200 response with the index.html body and the URL stays unchanged.https://example.com/assets/app.js; verify a 200 with the JavaScript file, not index.html.https://example.com/nonexistent; confirm a 200 with index.html and that the rendered page shows your NotFound component.Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.