linux systemd service on port 80 - node.js

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.

Related

Two Nginx server block only one works with React app

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.

NodeJs Lan application on RPi to google cloud platform to custom domain

I have been able to set up my virtual machine on google cloud platform and am able to SSH into my RPi successfully using this tutorial:
https://medium.com/jj-innovative-results/how-to-access-a-raspberry-pi-anywhere-with-reverse-ssh-and-google-cloud-platform-59b6a89501a
Now I want to transfer HTTP data on port 8080 where my LAN application is hosted on the RPi instead of SSH data on port 22 to my virtual machine. How do i go about this and is it possible?
From there i plan on buying a domain to view my LAN app on the internet. I don't want to use services such as remoteit/zerotier to do this
Please help
For security reasons, I am recommending setting up a proxy between the Internet and your SSH server. You can skip steps #1 and #2 and use a port number above 1024 such as 8080. Never run the SSH server directly on port 80 as that requires privilege.
STEP 1)
Install Apache or Nginx.
STEP 2)
Set up a proxy in Apache/Nginx to forward connections on port 80 to port 8080.
Example configuration for Nginx:
server {
listen 80;
server_name example.com;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass "http://127.0.0.1:8080";
}
}
STEP 3)
Configure the VM SSH server to allow port forwarding option AllowTcpForwarding.
Setup the tunnel to open port 8080 on the VM and forward to the listening port on your Raspberry Pi (example 9000).
Example SSH command to run on the raspberry Pi:
ssh -R 8080:127.0.0.1:9000 <VM IP Address> <Your credentials>
Details. This command opens port 8080 on the public VM server and forwards traffic back to your system to port 9000.
Note: I did not test the SSH command, but this should be correct. There are many examples on the Internet such as link. This answer will help you understand how traffic is routed (forwarded).
STEP 4)
Configure the application running on the Raspberry Pi to listen on port 9000 (example).
Summary, the client connects to VM port 80 which forwards to VM port 8080 which forwards over the SSH tunnel to the Raspberry Pi which has an application listening on port 9000.
Of course, you can change the port numbers, I used unique port numbers to prevent confusion.

DigitalOcean Ubuntu droplet not serving port 80

I have a simple Python server on a DigitalOcean Ubuntu droplet that should serve the index.html file in the /dist folder:
port = 8000
os.chdir(os.path.join(os.path.dirname(__file__), 'dist'))
Handler = http.server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(('', port), Handler)
print('Serving at port ', port)
httpd.serve_forever()
I ran 'sudo ufw allow 80/tcp' to open the firewall and if I run ufw status it shows port 80 as being open to everybody. I ran 'sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8000' to redirect traffic from port 80 to port 8000.
If I run nmap from another box, the only open port is ssh on 22. Port 80 is filtered. Navigating to the host in my browser results in a connection timeout. What could be causing this?
It turns out I had to enable the DigitalOcean firewall and apply the correct rules, otherwise without the firewall it was just blocking ports by default.

google cloud pm2 start nodejs successfully but not accessible

I started node server successfully with pm2 but I couldn't access to my host.
I opened port on google cloud.
OS: Debian.
node version: v8.12.0
pm2 version: 3.2.2
I tried pm2 kill and restart but nothing happend. What am I wrong?
Take the following steps to remediate your connectivity issue:
Check to see what programs are running and what port(s) they are listening on. See if you can identify your program running:
sudo netstat -tnlp If you see a node process, notice the port it is listening on. Does this match 3000? If so, check to see what network address it is listening on: Does it show 0.0.0.0 or does it show 127.0.0.1? If it shows 127.0.0.1 then your application is only listening on localhost and you need to modify it to listen on 0.0.0.0.
Check the local firewall to see if you have allowed port 3000 by running sudo iptables -nL. If you do not see ANY rules period and see "policy ACCEPT" then you're ok. Otherwise, if you do not see TCP port 3000 then we need to add an allow/permit rule. To do so run sudo ufw allow 3000. If the ufw command is not found then you can run sudo iptables -A INPUT -p tcp --jport 2195 -j ACCEPT followed by sudo /etc/init.d/iptables save.
If you still cannot connect to your application please provide the output to the following commands:
sudo iptables -nL
sudo netstat -tnlp
gcloud compute firewall-rules list (if gcloud cli is installed, otherwise another screenshot of your firewall rules under your network settings in GCP console).
I config nginx default as a proxy to nodejs server. And It still work!
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;
Check first with curl http://localhost:3000
Make sure you open your project firewall port 3000
https://console.cloud.google.com/networking/firewalls/list?project=xxxx
Run this SELINUX, I'm on centos7
sudo setsebool -P httpd_can_network_connect on
sudo setsebool -P httpd_enable_homedirs on
sudo chcon -Rt httpd_sys_content_t /home/admin/www
sudo systemctl restart nginx

Running Node app via PM2 on port 80

I have an express that I want to run on port 80. --> app.listen(80);
I'm using PM2 to manage the app (restarting, stopping, monitoring, etc.) . I have a deployment shell script whose last command is PM2 restart index. From the console output, I see no errors and PM2 reports that it successfully completed the command. Yet when I got to my.ec2.ip.address:80 the site is not up. Furthermore, if I run node index.js in my server project directory, I get a Error: listen EACCES 0.0.0.0:80. This makes some sense to me as port 80 is below 1024 and therefore a privileged port. sudo node index.js will allow the launch to work.
I'm a newbie to unix, servers, permissions, and deployment, so in addition to the solution, an explanation of the fundamental concepts contributing to my problem would be greatly appreciated. For instance.. is it bad to simply run my node app as super-user? Is it good practice to run PM2 (therefore possibly running node as..?) root/super-user? The command sudo PM2 restart index leads to sudo: pm2: command not found. Why is PM2 not found when running sudo PM2.. if PM2 is in my path?
Ultimately though, when using PM2 how can I ensure that my server runs on port 80? not found.
Dont use port 80, run on other port like 8080 and redirect 80 to that port with this command
sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
It's good to run as little as possible as a priviliged user, as you want to restrict the potential damage in case someone exploits your program. You don't want to run your Node code as root unless you absolutely have to.
Therefore, it's better to run your Node program on an unprivileged port (say, port 8000), and instead have a lightweight web server such as Nginx listen on port 80 and simply forward traffic to your Node program.
If you want to go with Nginx, you can use this configuration to do exactly what I described above, and then just listen with your Node program on port 3000:
server {
listen 80 default;
listen [::]:80 default;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
}
}
I had the same issue, for the ubuntu server.
Fixed with the tutorial below.
sudo apt-get install libcap2-bin
sudo setcap cap_net_bind_service=+ep /usr/local/bin/node
https://www.digitalocean.com/community/tutorials/how-to-use-pm2-to-setup-a-node-js-production-environment-on-an-ubuntu-vps
Also here is another solution from PM2
sudo apt-get install authbind
sudo touch /etc/authbind/byport/80
sudo chown %user% /etc/authbind/byport/80
sudo chmod 755 /etc/authbind/byport/80
https://pm2.keymetrics.io/docs/usage/specifics/#listening-on-port-80-w-o-root
Though, you may have solved the issue but for the one who comes here facing the same issue, this worked me :
For just troubleshooting, run your app using sudo npm start. If your app runs normally then you need to bind port 80 with the help of authbind package. Run these commands :
sudo apt-get install authbind
sudo touch /etc/authbind/byport/80
sudo chown %user% /etc/authbind/byport/80
sudo chmod 755 /etc/authbind/byport/80
Replace %user% with the user you run pm2. Mine was ubuntu by default.
Set start command in your package.json file to pm2 start <server_file_name>.
Run the app using npm start. It should work !
After lot of time spent configuring nginx, finally uninstall it and followed A.J. suggestion to configure iptables. Thank you A.J.
sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
But, if anyone know a perfect tutorial to configure nginx, would be a great help.

Resources