Two Nginx server block only one works with React app - linux

I want to host several react app on my linux(CentOS) server with nginx.
currently I have two server block in nginx.conf.
First server is where I proxy different request to different server.
Second server is my react app.
I couldn't get my react app host by nginx.
Block 1
server {
listen 80
server_name localhost
root /usr/share/nginx/html
...
location /app1/ {
proxy_pass http://localhost:3010
}
...
}
Block 2
server {
listen 3010;
listen [::]:3010;
server_name localhost;
root /home/administrator/Projects/app1/build;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
When I using telnet to check the server is hosting or not. only port 80 is listening.
No server is listening on port 3010.
How should I change my Nginx configuration to make it works?
Update
I check the nginx error log and I got
1862#0: bind() to 0.0.0.0:3010 failed (13: Permission denied)
I've search on it and there are a lot answer about non-root user cannot listen to port below 1024
But the server is trying to bind on 3010
Do I still have to add run nginx by root?

This is probably related to SELinux security policy. If You check on the below command and see http is only allowed to bind on the list of ports.
[root#localhost]# semanage port -l | grep http_port_t
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
Maybe you can use any of the listed ports or add your custom port using the below command
$ semanage port -a -t http_port_t -p tcp 3010
If semanage command is not installed, you can check using yum provides semanage command to identify which package to install.

Related

Nginx Configuration for node Js application + Docker

I have a nodeJS application which is configured as a docker container.For making the application up and running, i was initially using 443 as the port - which gave a message 443 is a privileged port and updated the .yml with 8443 as the port.
Previously i used to give the url like - https://abc-acde.xyz , but now have to give https://abc-acde.xyz:8443 the port also along with domain name.
To resolve this i installed nginx to use it as a proxy to reroute the request.
The nginx config file is configured with the key , certs along with the server details - the configuration snippet of the conf file is below :
server {
listen 443 ssl;
server_name abc-acde.xyz;
ssl_certificate /opt/ssl/abc-acde.xyz/abc_acde_xyz.cer;
ssl_certificate_key /etc/ssl/ssl_signed_certs/abc-acde.xyz.key;
}
After this run the command - systemctl restart the nginx
Hope this configuration will help me to use the url as it was earlier - use without the port
Thanks in advance,
Rahul

Can't redirect traffic to localhost with nginx and docker

I'm new to Docker and nginx so this may be a simple question but I've been searching through question/answers for a while and haven't found the correct solution.
I'm trying to run an nginx server through docker to reroute all requests to my.example.com/api/... to localhost:3000/api/...
I have the following Dockerfile:
FROM nginx
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
and the nginx.conf file:
server {
server_name my.example.com;
location / {
proxy_pass http://localhost:3000/;
}
}
When I make the calls to the api on localhost:3000 this works fine but when I try to run against my.example.com I get a network error that the host isn't found. To be clear the domain I want to 'redirect' traffic from to localhost host is a valid server address, but I want to mock the api for it for development.
This isn't working because your nginx proxying request to localhost which is container itself but your app is running on host's port 3000 -- outside of container. check this article
change
proxy_pass http://localhost:3000/;
  to
proxy_pass http://host.docker.internal.
add 127.0.0.1 example.com my.example.com in etc/hosts

Nginx proxy_pass to docker container doesn't work

I have two identiacal docker containers running on different ports on CentOS7 server. Older version runs on port 81, newer one on port 8080 (82,83 were checked as well).
When I'm trying to proxy second container and change port from 81 to 8080 I receive nginx error message (HTTP/1.1 502 Bad Gateway).
Nginx is not in a container. I just have it installed on the server.
Here is my proxy_pass setting:
location / {
proxy_pass http://0.0.0.0:8080/;
}
And some additional information:
nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
If I try to access containers directly via their ports everything works fine.
curl 0.0.0.0:81
{"msg":"Phone Masks service"}
curl 0.0.0.0:8080
{"msg":"Phone Masks service"}
nginx version: nginx/1.16.1
Docker version 19.03.4, build 9013bf583a
Full server config is pretty standard, I didn't change anything except proxy_pass setting
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://0.0.0.0:8080/;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
The command I use to start the container:
sudo docker run --rm -it -p 8080:8080 -e PORT="8080" api
sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
47ef127e3e49 api "/start.sh" 26 minutes ago Up 26 minutes 80/tcp, 0.0.0.0:8080->8080/tcp infallible_borg
5d5fe891ba30 api "/start.sh" 7 hours ago Up 7 hours 80/tcp, 0.0.0.0:81->81/tcp hopeful_cerf
This is SElinux related:
setsebool -P httpd_can_network_connect true
According to this thread:
The second one [httpd_can_network_connect] allows httpd modules and scripts to make outgoing connections to ports which are associated with the httpd service. To see a list of those ports run semanage port -l | grep -w http_port_t

linux systemd service on port 80

I try to create systemd service on centos7:
[Unit]
Description=Node.js Weeki Server
Requires=After=mongod.service
[Service]
ExecStart=/usr/bin/node /var/node/myapp/bin/www
Restart=always
StandardOutput=syslog # Output to syslog
StandardError=syslog # Output to syslog
SyslogIdentifier=nodejs-weeki
User=weeki
Environment=NODE_ENV=production PORT=80
[Install]
WantedBy=multi-user.target
When i use port 8080 the service start successfully, but when i change the port to 80, the service failed to start.
I try to open the firewall with the command:
firewall-cmd --zone=public --add-port=80/tcp --permanent
But it still not working.
See the good advises that you got in the comments by arkascha.
First of all - what's the error?
What you can do to test if it's a problem of the user not being able to bind to low ports is trying use ports like 81, 82, 83 etc. If you still cannot bind to those ports then you likely don't have the permission. If you can, then it's not about permissions and the port is already used by some other process.
To see if you can open a given port by that user try running netcat:
nc -l 80
where 80 is the port number. Try low ports like 80, 81, 82 and high ports like 8080, 8081, 8082.
To see if anything is listening to that port try running:
curl http://localhost:80/
or:
nc localhost 80
To see open ports on your system run:
netstat -lnt
To see if other instances of your program are running, try:
ps aux | grep node
ps aux | grep npm
ps aux | grep server.js
If all else fails, you can restart and see if the problem remains:
sudo shutdown -r now
That should give you a clean state with no old processes hanging around.
Update
What you can do to listen on port 80 without running as root.
There are few things that you can do:
Drop privileges
You can start as root and drop privileges as soon as you open a port:
app.listen(80, function () {
try {
process.setuid('weeki');
process.setgid('weeki');
console.log('Listening on port 80');
console.log('User:', process.getuid(), 'Group:', process.getgid());
} catch (e) {
console.log('Cannot drop privileges');
process.exit(1);
}
});
Pros: You don't need to use anything other than your Node program.
Cons: You need to start as root.
See:
https://nodejs.org/api/process.html#process_process_setuid_id
https://nodejs.org/api/process.html#process_process_setgid_id
Reverse proxy
Your Node app can listen on high port like 3000 and you start nginx or other web server to listen on port 80 and proxy requests to port 3000.
Example nginx config:
server {
listen 80;
server_name example.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;
}
}
Pros: You don't need to start as root. You can host multiple domains on the same server. You can serve static content directly by nginx without hitting your Node app.
Cons: You need to install and run another software (like nginx).
Route tables
You can redirect the incoming traffic on port 80 to port 3000 with iptables:
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000
(you need to run it as root)
Pros: No new software to install. No need to run the Node app as root.
Cons: Static content is served by your Node app. Hosting more than one app per server is not practical.
See:
https://help.ubuntu.com/community/IptablesHowTo
Allow low port for non-root
This is not always available but also an option. You can use the CAP_NET_BIND_SERVICE capability in the Linux kernel:
CAP_NET_BIND_SERVICE
Bind a socket to Internet domain privileged ports (port
numbers less than 1024).
Pros: No need to run other software. No need to start Node app as root. No need to mess with route tables.
Cons: Not practical to host more than one app per server. Needs using capabilities that may not be available on every system.
See:
http://man7.org/linux/man-pages/man7/capabilities.7.html
User should have root privileges to open ports below 1024.

ExpressJS Server - respond to host header with shared port

Lets say I have corporatewebsite.com listening on port 80. Which is an appache / WordPress site.
I have a node application that I'd like to respond to sub.corporatewebsite.com
The node application is running Express currently. I can get it to listen to a separate port at the moment, but my service won't start if it's pointed to port 80 since it's already in use.
How can I have both apache and node listening to port 80, but having node responding to the subdomain?
You could use a reverse proxy like Nginx to route your subdomains.
Here is an example of nginx configuration, you might probaly have to complete according to your project and server :
server {
listen 80;
server_name corporatewebsite.com;
location / {
[ ... some parameters ... ]
include proxy_params; // Import global configuration for your routes
proxy_pass http://localhost:1234/; // One of your server that listens to 1234
}
}
server {
listen 80;
server_name sub.corporatewebsite.com;
location / {
[ ... some parameters ... ]
include proxy_params;
proxy_pass http://localhost:4567/; // The other server that listens to 4567
}
}
You have to configure, for example, apache2 listening to port 1234 while nodejs is listening to port 4567.
If you do like this, a good practice is to block direct access from the outside to your ports 1234 and 4567 (using iptables for example).
I think this post could be useful to you : Node.js + Nginx - What now?

Resources