Webpack development server seperate subdomain proxied by nginx - node.js

im currently stuck on a probem with the webpack-dev-server which listen on a wrong domain with a wromng port. I've dockerized my Symfony application having 3 container, node, php and nginx. On the Node container the webpack-dev-server is running with the following (shortened) configuration
output: {
filename: '[name].[hash].js',
chunkFilename: '[name].[chunkhash].js',
path: Path.resolve(__dirname, 'web/static'),
publicPath: '/static/'
},
devServer: {
contentBase: Path.join(__dirname, 'web'),
host: '0.0.0.0',
port: 8080,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
},
disableHostCheck: true,
open: false,
overlay: true,
compress: true
},
The nginx is configured to find the php application on www.application.box (docker port mapping 80 => 80)
The webpack-dev-server is reachable on static.application.box (proxied port 80 to 8089) and running on port 8080. also port 8080 is mapped to the host.
While all assets correctly resolved from static.application.box/static/some-assets.css/js the socketjs-node/info request as well as the websocket it self are running on www.application.box:8080/socketjs-node/info?t= (which is working since the port is mapped to the node container)
I've tried several things, but without success. So how can i modify the webpack-dev-server/nginx configuration to get the js and websocket on static.application.box/socketjs-node/info?t ?

I ran into the same problem with webpack-dev-server a week ago, but it should be noted that I modified /etc/hosts to have seperate project.local domains and that I used https.
Description:
In this case the webpack-dev-server ran on a docker container client:8080 and was proxied to client.project.local:80 via nginx
Like you I didnt find a way to configure webpack-dev-server to use my host and port so I created another nginx proxy especially for that :8080/sockjs-node. [1]
But then I had the problem, that the dev-server tried to access https://client.project.local:8080/sockjs-node/info?t=1234567890
Which is a port too much for nginx, since client.project.local is already a proxy to client:8080. So I added in the webpack.conf.js config.output.publicPath = '//client.project.local/ and ... voilĂ :
https://client.project.local/sockjs-node/info?t=1234567890.
works like a charm.
Configs
webpack.conf.js:
const fs = require('fs')
const sslCrt = fs.readFileSync('/path/to/ssl/ca.crt')
const sslKey = fs.readFileSync('/path/to/ssl/ca.key')
// ...
{
// ...
devServer: {
hot: true, // <- responsible for all of this, but still dont wanna miss it ;)
inline: true,
compress: true,
host: process.env.HOST, // set in Dockerfile for client container
port: process.env.PORT, // set in Dockerfile for client container
disableHostCheck: true, // when manipulating /etc/hosts
headers: { 'Access-Control-Allow-Origin': '*' },
https: {
cert: sslCrt,
key: sslKey
},
// ...
}
output: {
publicPath: '//client.project.local/' // host from /etc/hosts (note // at beginning)
},
}
nginx client config:
# http
server {
listen 80 default;
listen [::]:80 default ipv6only=on;
server_name www.client.project.local client.project.local www.project.local project.local;
# your other config like root, access_log, charset ..
location / {
proxy_pass https://client:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
# https
server {
listen 443 ssl default;
listen [::]:443 ssl default ipv6only=on;
ssl_certificate project.local.crt;
ssl_certificate_key project.local.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl on;
server_name www.client.project.local client.project.local www.project.local project.local;
# your other config like root, access_log, charset ..
location / {
proxy_pass https://client:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
# http/s websocket for webpack-dev-server
server {
listen 8080 default;
listen [::]:8080 default ipv6only=on;
ssl_certificate project.local.crt;
ssl_certificate_key project.local.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl on;
server_name www.client.project.local client.project.local www.project.local project.local;
# your other config like root, access_log, charset ..
location /sockjs-node/ {
proxy_pass https://client:8080/sockjs-node/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
Remember to expose port 8080 for nginx container aswell in for example in docker-compose.yml. I added a shortend version for the sake completion
docker-compose.yml
version: "3"
networks:
project-net-ext:
project-net:
internal: true
driver: bridge
services:
client:
hostname: client
build: ./container/client
volumes:
- ./path/to/code:/code:ro # read-only
# write needed only for initial package download
ports:
- "8080:8080"
networks:
- project-net
# project-net-ext only needed for initial package download
nginx:
hostname: nginx
build: ./container/nginx
volumes:
- ./path/to/code:/code:ro # read-only
# write needed only for initial package download
ports:
- "80:80" # http
- "443:443" # https
- "8080:8080" # webpack-dev-server :8080/sockjs-node/info
links:
- client
networks:
- project-net # needed for nginx to connect to client container,
# even though you've linked them
- project-net-ext # nginx of course needs to be public
[1]: I dont know if its considered to be dirty. At least it feels a bit like it is, but it works and as the name suggests: Its a dev-server and once you npm build for productive, its gone - for ever

this can be fixed by setting devServer.sockPort: 'location'
webpack.config.js:
devServer {
sockPort: 'location'
// ...
}
Here's a complete nginx.conf that will allow you to proxy webpack-dev-server without requiring any changes other than sockPort
nginx.conf:
events {}
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8081;
# uncomment if you need ssl
# listen 4443 ssl;
# ssl_certificate cert.pem;
# ssl_certificate_key privkey.pem;
location / {
# webpack-dev-server port
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Host localhost;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}

Related

Express server not working on reverse proxy (NGINX)

I am testing my express server running on proxy. My nginx config file for in sites-available is:
server {
server_name open.yousico.com;
gzip on;
gzip_proxied any;
gzip_types application/javascript application/x-javascript text/css text/javascript;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_min_length 256;
location /_next/static/ {
alias /var/www/yousi-website/.next/static/;
expires 365d;
access_log off;
}
location / {
proxy_pass http://127.0.0.1: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;
}
location /api {
rewrite ^/codify(.*) $1 break;
proxy_pass "http://127.0.0.1:3001";
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/open.yousico.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/open.yousico.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = open.yousico.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name open.yousico.com;
return 404; # managed by Certbot
}
My server file for my express server listening on 3001 is:
const express = require('express');
const app = express();
app.listen(3001, console.log("server is running on 3001"));
app.get('/', (req, res) => {
res.send('API is running');
});
app.get('/hello', (req, res) => {
res.send('Hello World');
});
I tested this express server on my local machine, and it seems to be working fine, but when I deploy it to my cloud server, it displays "Cannot GET /api", is there something wrong with my config file? My understanding is that I set my location to /api and direct it to port 3001, and I'm sure that the server is running on 3001.
"Cannot XXX /YYY" is the Express default response when there is no handler for method XXX for path YYY.
In your case, I don't see an app.get("/api", ...) handler in your server code, so the error is quite warranted.
The rewrite statement in your nginx config,
rewrite ^/codify(.*) $1 break;
doesn't make sense either since there's no way for location /api to match /codify.
If you meant to strip the /api out before the URL is passed to your Express server,
rewrite ^/api(.*) $1 break;
in which case /api would be passed as /, and that would match your app.get("/")...

Not found error with two Node projects served by NGINX with Docker

I'm learning Docker and my goal is to serve two Node.js projects whit same docker-compose using NGINX. My two project(A and B) are simple hello world:
'use strict';
const express = require('express');
// Constants
const PORT = 8301;
const HOST = '0.0.0.0';
const PATH = '/project-a';
// App
const app = express();
app.get(PATH, (req, res) => {
res.send('<h1>Hello World</h1><p>Project A</p>');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}${PATH}`);
Above there is A, B has the same code but change only port 8302 and path /project-b. Below the docker-compose:
version: '3.7'
services:
website_a:
image: project_a/node
build:
context: ./projects_a
dockerfile: Dockerfile
container_name: project_a
restart: always
command: sh -c "node server.js"
expose:
- 8301
website_b:
image: project_b/node
build:
context: ./projects_b
dockerfile: Dockerfile
container_name: project_b
restart: always
command: sh -c "node server.js"
expose:
- 8302
nginx:
image: node-project-multisite/nginx
build: nginx
container_name: multisite_project_nginx
ports:
- 80:80
depends_on:
- website_a
- website_b
And the nginx's conf:
server {
listen 80;
listen [::]:80;
server_name 127.0.0.1;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /project-a {
proxy_pass http://website_a:8301/project-a;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
# max uploadable file size
client_max_body_size 4G;
}
}
server {
listen 80;
listen [::]:80;
server_name 127.0.0.1;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /project-b {
proxy_pass http://website_b:8302/project-b;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
# max uploadable file size
client_max_body_size 4G;
}
}
Using the docker-compose without NGINX I can see both hello world, but with NGINX I can use only A, in B there is the message below:
Where I put a mistake?
You should use only one "server" since they share server_name and port
server {
listen 80;
listen [::]:80;
server_name 127.0.0.1;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /project-a {
proxy_pass http://website_a:8301/project-a;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
# max uploadable file size
client_max_body_size 4G;
}
location /project-b {
proxy_pass http://website_b:8302/project-b;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
# max uploadable file size
client_max_body_size 4G;
}
}

How to set up nginx reverse proxy with multiple node apps

I have two Vue.js apps that I want to run on the same domain (e.g., https://localhost:8080/app1 and https://localhost:8080/app2). Both apps run in separate docker containers, and i have set up a third docker container running nginx with a reverse proxy in order to have ssl.
I am able to visit the apps at the wanted locations, but there are some resources missing (images, fonts etc). I realize that my nginx server looks for them at https://localhost:8080/my_resource, but I can't figure out how to forward these to the correct locations (i.e., https://localhost:8080/app1/my_resource, and similar for app2).
I've tried using the "try_files" directive in nginx, like so:
location / {
try_files $uri $uri/ http://app1:8080 http://app2:8080
}
but it does not work.
Here is my nginx config file
server {
listen 80;
listen [::]:80;
server_name localhost;
return 301 https://$server_name$request_uri;
}
# Change the default configuration to enable ssl
server {
listen 443 ssl;
listen [::443] ssl;
ssl_certificate /etc/nginx/certs/my_app.crt;
ssl_certificate_key /etc/nginx/certs/my_app.key;
server_name localhost;
server_tokens 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_set_header X-Forwarded-Proto $scheme;
location / {
if ($http_referer = "https://localhost:8080/app1/") {
proxy_pass http://app1:8080;
break;
}
if ($http_referer = "https://localhost:8080/app2/") {
proxy_pass http://app2:8080;
break;
}
}
location /app1/ {
proxy_pass http://app1:8080/;
}
location /app2/ {
proxy_pass http://app2:8080/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
And this is my docker-compose
version: "3.6"
services:
app1:
image: "app1"
expose:
- "8080"
command: ["serve", "-s", "/app/app1/dist", "-l", "8080"]
app2:
image: "app2"
expose:
- "8080"
command: ["serve", "-s", "/app/app2/dist", "-l", "8080"]
nginx:
image: "nginx"
ports:
- "8080:443"
depends_on:
- "app1"
- "app2"
Thanks for any input :)
After a lot of trial and error, I found a solution. I do not think this is the optimal solution, but it's working. Here is my nginx configuration:
# Pass any http request to the https service
server {
listen 80;
listen [::]:80;
server_name localhost;
return 301 https://$server_name$request_uri;
}
# Configure the ssl service
server {
listen 443 ssl;
listen [::443] ssl;
ssl_certificate /etc/nginx/certs/my_app.crt;
ssl_certificate_key /etc/nginx/certs/my_app.key;
server_name localhost;
server_tokens off;
proxy_set_header Host $http_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;
location / {
proxy_intercept_errors on;
error_page 404 = #second;
proxy_pass http://app1:80;
}
location #second {
proxy_pass http://app2:80;
}
location /app1/ {
rewrite ^/app1(.*) /$1 break;
proxy_pass http://app1:80;
}
location /app2/ {
rewrite ^/app2(.*) /$1 break;
proxy_pass http://app2:80;
}
# 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;
}
}

Port numbers not hiding in nginx reverse proxy (next js server)

I am trying to deploy a next-js app by create-next-app, I have a custom express server like this -
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const nextApp = next({ dev })
const handle = nextApp.getRequestHandler()
const fs = require('fs')
nextApp.prepare()
.then(() => {
const server = express ()
let port = 3000;
let options = {
key: fs.readFileSync('some key..', 'utf-8'),
cert: fs.readFileSync('some cert..', 'utf-8'),
};
server.get(
...
)
let app = https.createServer(options, server)
.listen((port), function(){
console.log("Express server listening on port " + port);
});
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
I want to deploy this as the website when someone types the URL subdomain.maindomain.com so I saved two nginx configuration files like this -
/etc/nginx/sites-available/default AND /etc/nginx/sites-available/subdomain.maindomain.com
the default file contains this
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name maindomain.com www.maindomain.com;
location / {
# try_files $uri $uri/ =404;
proxy_pass http://localhost: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;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/maindomain.com/fullchain.pem;$
ssl_certificate_key /etc/letsencrypt/live/maindomain.com/privkey.pe$
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
and the subdomain.maindomain.com file looks like this
server {
if ($host = www.subdomain.maindomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = subdomain.maindomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
root /var/www/subdomain.maindomain.com/somecodefolder/;
index index.html index.htm index.nginx-debian.html;
server_name subdomain.maindomain.com www.subdomain.maindomain.com;
location / {
proxy_pass http://localhost: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;
# try_files $uri $uri/ =404;
}
}
if I'm typing https://subdomain.maindomain.com:3000, everything works fine, I see my website running. But when I type https://subdomain.maindomain.com (without the port number) it shows nothing. How can I get the content I want when I type just the url without the port number. I have tried many combinations, but could'nt do. someone please help i've been trying since 2 days.
Try with other applications in order to validate if something is wrong in your application.
Configure nginx to use domain instead ports are not complex. Just add https configurations but the main configurations will be the same.
Steps
npm install
node main_domain.js
node subdomain.js
Check if webs are working:
Add the following lines to your /etc/hosts. This will help us to use domains without enterprise web hosting company register.
127.0.0.1 maindomain.com
127.0.0.1 subdomain.maindomain.com
Create a file in /etc/nginx/conf.d called maindomain.com.conf or whatever you want but with .conf
server {
listen 80;
server_name maindomain.com;
location / {
proxy_pass http://localhost:3000/;
}
}
Create a file in /etc/nginx/conf.d called conf.d/subdomain.maindomain.com.conf or whatever you want but with .conf
server {
listen 80;
server_name subdomain.maindomain.com;
location / {
proxy_pass http://localhost:3001/;
}
}
Restart the nginx
service nginx restart
And now, you could use a domain instead ip:port
Try to change from
proxy_pass http://localhost:3000;
Into
proxy_pass http://127.0.0.1:3000;

How to use nginx proxy_pass subroutes from node app?

I have a node app running on port 8002 with different subroutes like '/login' or '/facebook', i also have nginx (v1.6.0) and the following config:
server {
listen 80;
server_name my-ghost-blog.com ;
client_max_body_size 10M;
location / {
proxy_pass http://localhost:2368/;
proxy_set_header Host $host;
proxy_buffering off;
}
location ~ ^/(sitemap.xml) {
root /var/www/ghost;
}
location ~ ^/(robots.txt) {
root /var/www/ghost;
}
#proxy to a node app running on 8002 port
location ^~ /auth/ {
proxy_pass http://localhost:8002/;
}
}
when i go to '/auth/' it works, but when i try to go to a node app'subroute, 404 appears because nginx dont know how to handle it.
any ideas?
thanks

Resources