In MacOS, I usually run my project in localhost by sudo PORT=443 HTTPS=true ./node_modules/.bin/react-scripts start
. As a result, https://localhost/#/start
works in a browser.
Now, to run third-party authentications in localhost, I need to run nginx. Here is my /usr/local/etc/nginx/nginx.conf
:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream funfun {
server 178.62.87.72:443;
}
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/ssl/localhost/localhost.crt;
ssl_certificate_key /etc/ssl/localhost/localhost.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_timeout 1d;
ssl_stapling off;
ssl_stapling_verify off;
add_header Strict-Transport-Security max-age=15768000;
add_header X-Frame-Options "";
proxy_ssl_name "www.funfun.io";
proxy_ssl_server_name on;
location ~ /socialLoginSuccess {
rewrite ^ '/#/socialLoginSuccess' redirect;
}
location ~ /auth/(.*) {
proxy_pass https://funfun/10studio/auth/$1?$query_string;
proxy_set_header Host localhost;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Accept-Encoding "";
proxy_set_header Proxy "";
proxy_pass https://localhost/;
# These three lines added as per https://github.com/socketio/socket.io/issues/1942 to remove socketio error
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
include servers/*;
}
However, launching the nginx returns me the following errors:
$ sudo nginx
nginx: [emerg] bind() to 0.0.0.0:443 failed (48: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (48: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (48: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (48: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (48: Address already in use)
nginx: [emerg] still could not bind()
It seems that, nginx has conflit with the app running on 443. Does anyone know why?
Additionally, could anyone tell me what’s the purpose of the block location / { ... }
in my nginx configuration file?
2
Answers
Any port can be bound once to given interface. Now, if you run your react application server and it already bind port
443
on interface0.0.0.0
which in this case is used as kind of wildcard which means "listen on port 443 on all interfaces on my computer" then any other application can’t use this port because is already taken. In your nginx configuration you can see line which says that it also want to use port 443:You have (at least) 2 choices to fix that error:
PORT=443
in your local applicationNext –
location / { ... }
means that all request starting from/
which are virtually all requests except these catched in the two previouslocation
blocks, will be forwarded to another web server located athttps://localhost/
with some additional headers. This is called reverse proxy.Only one application can bind/listen on a given port at a time.
You started your app running on port 443:
sudo PORT=443 HTTPS=true ./node_modules/.bin/react-scripts start
Then when you tried to start nginx also on port 443 it fails because your app is already using 443.
To fix this:
3000
):sudo PORT=3000 HTTPS=true ./node_modules/.bin/react-scripts start
proxy_pass https://localhost:3000;
Additionally, I would suggest that you do SSL (https) termination on nginx and let nginx connect to your app on localhost insecurely to reduce other problems. Currently it looks like you are doing ssl termination on nginx and then another ssl connection/termination to your app/upstream. This really isn’t necessary when connecting on localhost or over a secure/private network (e.g. within AWS VPC).
3000
):HTTPS=true
fromsudo PORT=3000 HTTPS=true ./node_modules/.bin/react-scripts start
proxy_pass http://localhost:3000;
For production you should really always run nginx in front of your apps. This allows you to easily do ssl termination, load balancing (multiple apps/upstreams) as well as serving static files (jpg, css, etc) without running through nodejs or other application server. It will scale better. Right tool for the right job.
For local development purposes you can just work against the local insecure http://localhost:3000. If you really hate using port 3000 for some reason then you can of course change that using NODE_ENV in tandem with dotenv or similar in order to switch the port your app uses when in development mode vs production. There really isn’t any reason you need to use https/443 on localhost during development. You won’t be able to get a trusted SSL cert for localhost so there really isn’t any point…it just makes your life more difficult.
I have no issues testing oauth login flows against http://localhost:3000 with google for instance.