nginx config for nuxt on centos7
The Nuxt ecosystem has never been more exciting! In 2026, we’re witnessing unparalleled developer experience, blazing-fast performance, and incredible flexibility thanks to Nuxt’s advanced rendering strategies and the powerhouse Nitro server. From highly dynamic SSR applications to hybrid behemoths leveraging SSG for static parts and API routes for dynamic interactions, Nuxt 4 (or perhaps even Nuxt 5 by now!) delivers on every front.
But as developers, we know that the magic doesn’t stop at nuxi build. Getting your meticulously crafted Nuxt application into the hands of users requires a robust, performant, and secure deployment strategy. While cloud providers offer myriad options, there’s a timeless, rock-solid workhorse that continues to serve as the front-door for countless web applications: Nginx.
Today, we’re going to dive deep into configuring Nginx for your modern Nuxt application, specifically on a CentOS 7 server. “CentOS 7 in 2026?” you might ask. Absolutely! Many enterprise environments still rely on its stability, and understanding how to effectively bridge cutting-edge Nuxt with a battle-tested server stack is an invaluable skill.
Why Nginx is Your Nuxt App’s Best Friend
Think of Nginx as the ultimate bouncer, security guard, and traffic controller for your Nuxt application. Here’s why it’s indispensable, especially for Nuxt’s diverse rendering modes:
- Reverse Proxy: Nuxt’s Nitro server, whether running in SSR mode or handling API routes in a hybrid setup, is a Node.js process listening on a specific port (e.g.,
localhost:3000). Nginx sits in front of it, accepting requests on standard HTTP/HTTPS ports (80/443) and forwarding them to your Nuxt process. This isolates your application, enhances security, and allows Nginx to handle public-facing concerns. - Static File Serving: For SSG pages or the static assets generated by Nuxt (
_nuxt/directory), Nginx excels at serving these files directly with unparalleled speed and efficiency. This offloads the Nuxt Node.js process, allowing it to focus solely on dynamic content. - SSL/TLS Termination: Nginx handles the complexities of encrypting traffic with HTTPS, managing SSL certificates (e.g., from Let’s Encrypt via Certbot), and ensuring secure communication without your Nuxt app needing to directly manage certificates.
- Performance Optimization: Compression (Gzip/Brotli), caching of static assets, HTTP/2 support, and intelligent load balancing (if you scale) are all Nginx’s forte, dramatically improving your application’s perceived performance.
- Security Layer: Nginx can block malicious requests, limit request rates, and protect your backend Nuxt server from direct exposure to the internet.
Setting Up Your Nginx Proxy for Nuxt (Hybrid/SSR Mode)
For a modern Nuxt application in 2026, the most common and powerful deployment model is hybrid rendering. This means you’re likely pre-rendering some pages as static HTML (SSG), serving others via SSR, and exposing API endpoints through Nuxt’s server routes. Nginx handles this beautifully by intelligently serving static files and proxying dynamic requests to your running Nuxt Node.js process.
Prerequisites:
Before we dive into Nginx, ensure you have:
- A built Nuxt application: Run
nuxi buildin your project. This will generate the.output/directory containing your server entry (.output/server/index.mjs) and public static assets (.output/public/). - Nginx installed on CentOS 7: If not, a quick
sudo yum install nginxusually does the trick. - Your Nuxt application running: Use a process manager like
pm2orsystemdto keep your Nuxt server alive. For example:pm2 start .output/server/index.mjs --name nuxt-app. Ensure it’s listening on a specific port, say3000.
The Nginx Configuration
We’ll create a new Nginx configuration file for your Nuxt app, typically located in /etc/nginx/conf.d/your-app.conf.
# /etc/nginx/conf.d/your-app.conf
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
# Redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# --- SSL Configuration (replace with your actual paths) ---
# Use Certbot (Let's Encrypt) for easy SSL certificate management
# Example paths after running `sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com`
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
# Stronger SSL settings for 2026 (consult current best practices)
ssl_protocols TLSv1.3 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256';
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# HSTS (Strict-Transport-Security) for a year
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# --- Root and Index ---
# Point Nginx to Nuxt's public directory for static assets
root /path/to/your/nuxt-app/.output/public;
index index.html;
# --- Performance Optimizations ---
# Gzip Compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Cache Control for static assets (e.g., _nuxt/ files)
# These often have content hashes, so they can be aggressively cached
location ~* \.(css|js|gif|jpe?g|png|webp|svg|woff2?|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri @nuxt_app; # Important for Nuxt's static assets, if not found, proxy to Nuxt app
}
# --- Proxying to Nuxt Application ---
location / {
# Check if a static file exists. If so, serve it.
# Otherwise, try to find an index.html (for SSG pages).
# If neither, proxy the request to the Nuxt Node.js process.
try_files $uri $uri/index.html @nuxt_app;
}
# Named location for proxying to the Nuxt Node.js server
location @nuxt_app {
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_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1; # Required for WebSockets
proxy_set_header Upgrade $http_upgrade; # Required for WebSockets
proxy_set_header Connection "upgrade"; # Required for WebSockets
proxy_redirect off;
proxy_buffering off; # Important for real-time applications or long-polling
# The internal address and port of your running Nuxt application
proxy_pass http://localhost:3000;
}
# --- Error Pages ---
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html; # Default Nginx error page location
}
}
Key Configuration Elements Explained:
listen 80&return 301 https://$host$request_uri;: Ensures all HTTP traffic is automatically redirected to HTTPS, a non-negotiable best practice in 2026.listen 443 ssl http2;: Enables HTTPS with HTTP/2, significantly improving load times by allowing multiple requests over a single connection.ssl_certificate&ssl_certificate_key: Paths to your SSL certificates. Highly recommend using Certbot for Let’s Encrypt. It handles certificate generation, renewal, and Nginx config updates automatically.root /path/to/your/nuxt-app/.output/public;: This is crucial. It tells Nginx where to find your static assets (images, CSS, JS, and pre-rendered HTML files). Remember to replace/path/to/your/nuxt-app/with your actual project path.gzip on;: Enables Gzip compression for supported file types, reducing bandwidth usage and improving load times.location ~* \.(css|js|gif|jpe?g|png|webp|svg|woff2?|ttf|eot)$: This block defines aggressive caching for static assets. Nuxt’s build process generates content-hashed filenames for static assets (e.g.,app.c0a1b2d3.js), so you can safely cache them for a very long time (expires 1y).try_files $uri $uri/index.html @nuxt_app;: This is the heart of the hybrid approach.- Nginx first tries to find a static file matching the URI (
$uri). This covers all your Nuxt’s.output/publicassets, including SSG-rendered pages. - If not found, it tries to find an
index.htmlwithin a directory matching the URI ($uri/index.html). This is for route-based directories. - If neither a static file nor an
index.htmlis found, it sends the request to the@nuxt_appnamed location.
- Nginx first tries to find a static file matching the URI (
location @nuxt_app: This block acts as the reverse proxy to your Nuxt Node.js process, sending all unhandled requests (SSR pages, API routes, or client-side navigations) tohttp://localhost:3000.proxy_set_header: These headers are vital for your Nuxt application to correctly receive information about the client (IP address, original host, protocol), especially important for features likeevent.context.ipin Nuxt 4/5 server routes.proxy_http_version 1.1;,Upgrade,Connection: These headers enable WebSocket support, which might be increasingly used in modern Nuxt applications for real-time features.
Nuxt 2026 Code Example (How Nginx Interacts)
To illustrate, consider a simple Nuxt application with an API route and a component fetching from it. Nginx will handle the /api route by proxying to your Nuxt server.
First, a Nuxt server route (e.g., server/api/hello.ts):
// server/api/hello.ts
export default defineEventHandler(async (event) => {
// Access headers proxied by Nginx
const realIp = getHeader(event, 'x-real-ip') || getHeader(event, 'x-forwarded-for');
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async work
return {
message: `Hello from Nuxt Nitro server in 2026!`,
timestamp: new Date().toISOString(),
yourIp: realIp,
protocol: getHeader(event, 'x-forwarded-proto')
};
});
Then, a Nuxt page or component using a composable to fetch from this route:
<!-- pages/index.vue -->
<template>
<div>
<h1>Welcome to Nuxt 2026!</h1>
<p v-if="data">{{ data.message }} ({{ data.timestamp }})</p>
<p v-if="data">Your IP: {{ data.yourIp }} via {{ data.protocol }}</p>
<p v-else>Loading...</p>
<button @click="refresh()">Refresh Data</button>
</div>
</template>
<script setup lang="ts">
const { data, refresh } = await useAsyncData('helloData', () => $fetch('/api/hello'));
</script>
When you visit / in your browser, Nginx will serve the pre-rendered index.html if it’s SSG. When the Nuxt app in the browser makes an fetch('/api/hello') request, Nginx sees /api/hello, realizes it’s not a static file, and proxies it to your running Nuxt server process, which then executes server/api/hello.ts.
Troubleshooting Tips & Common Pitfalls
Even with the best config, issues can arise. Here are some common ones and how to tackle them on CentOS 7:
- Nginx Configuration Errors:
- Syntax Check: Always run
sudo nginx -tafter editing your Nginx config. This checks for syntax errors without reloading Nginx. - Reload Nginx: If the syntax is fine,
sudo systemctl reload nginxto apply changes.
- Syntax Check: Always run
- Firewall Issues (
firewalldon CentOS 7):- Ensure HTTP (80) and HTTPS (443) ports are open:
sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --reload - Also, ensure the port your Nuxt app is running on (e.g.,
3000) is accessible internally if you have strict rules, or ensure it’slocalhostonly.
- Ensure HTTP (80) and HTTPS (443) ports are open:
- SELinux Problems:
- CentOS 7 often has SELinux enabled, which can prevent Nginx from accessing your Nuxt project’s directories or proxying to specific ports.
- Temporary fix (not recommended for production):
sudo setenforce 0 - Proper solution: Add SELinux contexts. For example:
sudo semanage fcontext -a -t httpd_sys_content_t "/path/to/your/nuxt-app/.output(/.*)?" sudo restorecon -Rv /path/to/your/nuxt-app/.output sudo semanage permissive -a httpd_t # if still having issues, temporarily make httpd permissive # For proxying to port 3000: sudo semanage port -a -t http_port_t -p tcp 3000 - Alternatively, you can put your Nuxt project inside
/var/www/htmlor similar standard Nginx-accessible paths.
- Nuxt Process Not Running:
- Verify your Nuxt application is actually running on the port Nginx is trying to proxy to (
localhost:3000in our example). Checkpm2 listorsudo systemctl status nuxt-app.
- Verify your Nuxt application is actually running on the port Nginx is trying to proxy to (
- Incorrect
rootortry_files:- If you’re getting 404s for static assets or your app isn’t loading, double-check the
rootdirective points to.output/publicand thattry_filesis configured correctly.
- If you’re getting 404s for static assets or your app isn’t loading, double-check the
- Proxy Headers Missing:
- If your Nuxt server routes aren’t getting client IP or protocol information, ensure all
proxy_set_headerdirectives are present and correct in yourlocation @nuxt_appblock.
- If your Nuxt server routes aren’t getting client IP or protocol information, ensure all
- Cache Busting:
- While Nuxt uses content hashes for
_nuxt/assets, ensure other static assets (e.g., images directly inpublic/) are either cached intelligently or have unique names when updated.
- While Nuxt uses content hashes for
Actionable Takeaways
Deploying modern Nuxt applications on a robust Nginx server, even on a platform like CentOS 7, offers a powerful and performant solution.
- Embrace Hybrid Rendering: Leverage Nuxt’s ability to combine SSG for speed and SSR/server routes for dynamism. Nginx is your perfect partner for this.
- Prioritize Performance: Utilize Nginx’s built-in features like HTTP/2, Gzip compression, and smart caching for static assets to deliver a snappy user experience.
- Secure Your Application: Always deploy with HTTPS, using SSL certificates (Let’s Encrypt + Certbot is your friend). Nginx adds a critical layer of security as the first point of contact.
- Automate Process Management: Use tools like
pm2orsystemdto ensure your Nuxt Node.js process stays online and resilient.
Mastering this deployment stack allows you to harness the full power of Nuxt’s cutting-edge features in a reliable, production-ready environment.
Discussion Questions
- With Nuxt’s evolving server capabilities (like edge deployments and serverless functions), how do you see the role of traditional reverse proxies like Nginx changing in the next few years? Do you think they will become less critical, or simply shift their focus?
- What are your go-to tools and strategies for monitoring Nuxt applications deployed behind Nginx, especially regarding performance bottlenecks and error detection?