document running nuxt dev server behind nginx + SSL + proxy
Environment
- Operating System:
Linux - Node Version:
v16.11.1 - Nuxt Version:
3-3.0.0-27235451.ece0e01 - Package Manager:
Yarn - Bundler:
Webpack - User Config:
- - Runtime Modules:
- - Build Modules:
-
Describe the bug
Trying to start development server for people on nginx engine. When i'm starting with cli nuxt, i'm getting infinite reloads on page with error WebSocket connection to wss://example.com:24678/_nuxt/ failed`. Is there any chance to start nuxt with proxy on nginx?
Reproduction
Just cloned default project.
Additional context
No response
Logs
Nothing in nuxt3
I think it can be prevented if we change connections from domain to ip address.
Anyway, can i modify it now in nuxt.config.js?
How does your nginx config look like?
@lustremedia
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
server {
listen 80;
listen 443 ssl;
server_name dev.domainname.pl;
gzip on;
gzip_types text/plain application/xml;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 1000;
# This is a cache for SSL connections
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1440m;
rewrite ^/(.*)/$ /$1 permanent;
location / {
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_redirect off;
proxy_buffering on;
proxy_cache_valid 200 1d;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_pass http://localhost:3000;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
}
}
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
@quartze A few changes have to be made to allow development to run smoothly as expected behind your NGINX Proxy with SSL.
Everything below was tested and works properly, so let me know if you encounter any issues.
- Modify your nuxt config to set vite's hmr
clientPortto443(default https / ssl port) andpathto"hmr/". Explanation: The vite server uses port24678for HMR by default, we are not going to change this. SettingclientPortto443will allow us to then use NGINX to proxy the request back to vite.
import { defineNuxtConfig } from "nuxt3";
export default defineNuxtConfig({
vite: {
server: {
hmr: {
protocol: "wss",
clientPort: 443,
path: "hmr/",
},
},
},
});
- Modify the NGINX conf for you site Firstly, web sockets require HTTP/1.1, so the following is required in either your server or location block
proxy_http_version 1.1; # required
proxy_set_header Upgrade $http_upgrade; # required
proxy_set_header Connection "upgrade"; # required
Add location block to match the hmr path /hmr that we set in step 1.
location /_nuxt/hmr/ {
proxy_pass http://localhost:24678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
@quartze I went ahead and modified your server block as needed: ps: I also made substantial improvements to your gzip compression, you should now get much faster load times ⚡️.
server {
listen 80;
listen 443 ssl;
server_name dev.domainname.pl;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types
application/atom+xml
application/geo+json
application/javascript
application/x-javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/xhtml+xml
application/xml
font/eot
font/otf
font/ttf
image/svg+xml
text/css
text/javascript
text/plain
text/xml;
# This is a cache for SSL connections
# ssl_session_cache shared:le_nginx_SSL:1m;
# ssl_session_timeout 1440m;
rewrite ^/(.*) /$1 break;
location / {
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_redirect off;
proxy_buffering on;
proxy_cache_valid 200 1d;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_pass http://localhost:3000;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
}
location /_nuxt/hmr/ {
proxy_pass http://localhost:24678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
@Diizzayy working perfectly. Thanks for rewriting my code. Can you add this to docs?
Hey, I had the same issue and this helped me. Makes sense to create a guide page with this setup similar to the previous version.
@quartze @bubooon having this setup added to the docs is a good idea. I'll get started on a PR.
Trying to start production server.The nuxt throw an error when i let http redirect to https on nginx.

Hi, I had the same issue with docker. I have nginx as proxy for https
here is my nginx config (I am not the author, my colleague made it)
port 80 is served by default so I have proxy for 443 and 24678 (WS)
if you forced ws protocol on https, then browser throws error due to trying communicate to unsecured endpoint from secured
https-proxy.conf
server {
listen 443 ssl http2;
server_name _;
location / {
proxy_pass http://app:80;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
ssl_protocols TLSv1.2;
ssl_certificate /var/https-proxy-cert.cert;
ssl_certificate_key /var/https-proxy-cert.key;
access_log /dev/stdout;
error_log /dev/stderr;
}
server {
listen 24678 ssl http2;
server_name _;
location / {
proxy_pass http://app:24678;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
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 "upgrade";
}
ssl_protocols TLSv1.2;
ssl_certificate /var/https-proxy-cert.cert;
ssl_certificate_key /var/https-proxy-cert.key;
access_log /dev/stdout;
error_log /dev/stderr;
}
and nuxt.config.js
export default defineNuxtConfig({
vite: {
server: {
hmr: {
protocol: 'wss',
},
},
}
});
I have added ssl to my server name and nuxt3 was a blank page when using npm run dev. In nuxt config i did what @Diizzayy commented.
vite: {
server: {
hmr: {
clientPort: 443,
path: "hmr/",
protocol: "wss",
},
},
}
And also added the " location /_nuxt/hmr/ " in nginx. After all that it worked. @Diizzayy Saved the day. Huge thx.
The config that @Diizzayy and @jamesallan93 mentioned was working perfect until RC-7 :( Let me know guys if you have another workaround please!
@kosmeln I'll have another look at the setup and update you guys accordingly on what changes may need to be made here
Thank you in advance @Diizzayy !
@kosmeln I just got around to checking this out, and the setup I mentioned above works just fine still.
Perhaps you can give me more details about your exact setup and what's not working properly
Sorry for late response @Diizzayy .
Before upgrading the hmr requests (if looking at dev tools) showed
Request URL: ws://localhost: 24678/_nuxt/hmr/
After upgrade the url changed to
Request URL: https://localhost/hmr/
So I had to tune vite server.hmr.path setting from
hmr: {
protocol: 'wss',
host: 'localhost',
clientPort: 443,
path: 'hmr/',
}
as you suggested earlier to
hmr: {
protocol: 'wss',
host: 'localhost',
path: '_nuxt/hmr/',
}
Still not sure if this is correct and what has changed with the upgrade. Please let me know if you have any insights or what I can check further. Thanks in advance.
Hi guys.
It work for me:
Nuxt 3 \ vite proxy.
I generate key and sert with mkcert.
Change package script to:
"dev": "nuxt dev --https --ssl-key key.pem --ssl-cert cert.pem"
https:localhost:3000 work nice. vite proxy work too.
Waiting for a good answer🤖
The final solution: open your mind and reflect on what you really need
After a week spent trying to get Nuxt3 working with SSL with Nginx for development.... I realized that I have no need of Nginx !!! My goal is to get Nuxt3 working in a domain with SSL. It was my principle that it should work behind the reverse proxy, but, after all, it is just a whim. so:
package.json
"scripts": {
...
"dev": "nuxi dev --port YOUR_PORT --host YOUR_IP --https", <-- use IP and --https !!
...
}
In your Unbound conf or hosts file add reference to your domain and your YOUR_IP
now open the browser on https://yourdomain.tld:YOUR_PORT :
- no hmr problems
- no wss problems
- no crazy Nginx configuration
- no infinite console errors
- no problem of any kind
- hot reloading work, all work as expected.
So as I see, there is a reasonable solution for this — should we maybe close this and add a small PR to add some docs to the "Going further" part in the nuxt docs?
Better replace node args with nuxt.conifg.ts configuration.
Is it possible to fix it ?
❗ Code below isn't working!
// nuxt.config.ts
devServer: {
host: "0.0.0.0",
port: 3000,
https: {
key: fileURLToPath(new URL("./stage.key", import.meta.url)),
cert: fileURLToPath(new URL("./stage.crt", import.meta.url)),
},
url: process.env.APP_URL,
},
So as I see, there is a reasonable solution for this — should we maybe close this and add a small PR to add some docs to the "Going further" part in the nuxt docs?
It is reasonable only in certain circumstances. We are using Docker and a reverse proxy container to make sure our development setup is as close to our production setup. The option to remove the reverse proxy and let Nuxt do the ssl would be a lot different from our production and therefore not reasonable for us.
(I read somewhere that letting Nuxt do ssl in production is not safe, am I right?)
Hi, this is my definitive and working setup for Nuxt3 with vite and Nginx
nuxt.config.js
server: {
hmr: {
protocol: 'wss',
clientPort: 443,
path: 'hmr/',
},
},
package.json
"dev": "nuxt dev --host localhost --port 3035"
domain.conf
map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default 7d;
}
upstream mydomain {
zone upstreams 64K;
server localhost:3035 max_fails=1 fail_timeout=2s;
keepalive 2;
}
server{
listen 443 ssl http2;
server_name mydomain.lan;
...
rewrite ^/(.*) /$1 break;
location /_nuxt/hmr/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://localhost:24678;
}
location / {
expires $expires;
sendfile on;
sendfile_max_chunk 512k;
aio on;
proxy_max_temp_file_size 0;
proxy_pass http://mydomain;
proxy_next_upstream error timeout http_500;
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; # PLEASE !! DO NOT ADD THIS !!!
proxy_redirect off;
proxy_buffering on;
proxy_cache_valid 200 1d;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_key $uri$is_args$args;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
}
}
enjoy :)
Just leaving a note for anyone who may be having issues with this solution after upgrading to [email protected], I was experiencing reload loops and WSS connection errors.
It seems like specifying a vite.server.hmr config along with a nginx proxy_pass directive is no longer required to get HMR working on a SSL dev server. Removing the HMR config from nuxt.config.ts and removing the location block for /_nuxt/hmr from the nginx config fixed the issue.
App work when removing proxy_pass from nginx config and vite.server.hmr from nuxt.config.ts
But HMR not work for me
Need to add this in server block on nginx config
location /_nuxt/ {
proxy_pass http://{localhost or container name}:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
We also had issues on 3.7.4 --- To clarify, we actually had issues just when we went to upgrade, not even necessarily related to 3.7.4 but its dependencies.. We had the same issues on at least 3.7.0-3.7.4. Had to add these two rules to our existing nginx proxy pass to get HMR to work as per @tibesyc comment. We didn't need the cache bypass, host rule, nor did we need the http_version change.
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
For anyone trying to run nuxt dev server behind a reverse proxy using latest nuxi CLI:
- HMR is now same port of the same server (3000)
- vite.server.hmr config should be removed
see https://github.com/nuxt/cli/issues/241#issuecomment-1745113589 for a working (apache2) example and feel free to open any issues in nuxt/cli repository if still having for setup.
Also worth to note, modern Nuxi can terminate SSL and listen on single port (including 80/443) or even tunnel to an external URL with custom domain. You probably can simplify your whole workflow, however hacking is always welcome!
@JefferySJones's answer worked for me with [email protected].
So glad to see others using Nuxt / SSL / Nginx Proxy, I was going crazy trying to find the error:
[Vue Router warn]: No match found for location with path "/_nuxt/"
@fabko reference to @JefferySJones solution worked, redeployed NGINX proxy with new settings and worked great. THANK YOU!
New problem in Nuxt 3.10.1, last config from 3.8.x do not work anymore.
my last problem after a lot configs was: SyntaxError: Failed to construct 'WebSocket': The URL 'wss://localhost:undefined/' is invalid
but now, I can not believe DevTools, hmr work !!:
[vite] connecting... [vite] connected.
so: nuxt.config.ts
vite: {
// no server block !
},
package.json
"dev": "nuxt dev --host localhost --port 3035"
nginx.conf
map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default 7d;
}
domain.conf
upstream mydomain {
zone upstreams 64K;
server localhost:3035 max_fails=1 fail_timeout=2s;
keepalive 2;
}
server{
listen 443 ssl http2;
server_name mydomain.lan;
...
rewrite ^/(.*) /$1 break;
location /_nuxt/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://mydomain;
}
location / {
expires $expires;
sendfile on;
sendfile_max_chunk 512k;
aio on;
proxy_max_temp_file_size 0;
proxy_pass http://mydomain;
proxy_next_upstream error timeout http_500;
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; # PLEASE !! DO NOT ADD THIS !!!
proxy_redirect off;
proxy_buffering on;
proxy_cache_valid 200 1d;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_key $uri$is_args$args;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
}
}
Our configuration for dev:
(only nuxt specific settings) nginx:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location ~ /_nuxt {
proxy_redirect off;
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_read_timeout 1m;
proxy_connect_timeout 1m;
proxy_pass http://mydomain:3000
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_cache_bypass $http_upgrade;
}
location / {
proxy_redirect off;
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_read_timeout 1m;
proxy_connect_timeout 1m;
proxy_pass http://mydomain:3000
}
}
We have a seperate nginx config for our (nginx) proxy, that does the ssl. Here we have also map $http_upgrade:
(whole file)
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name _;
ssl_certificate <path-server.crt>
ssl_certificate_key <path-server.key>
location / {
proxy_pass http://<point to webserver>
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}