How can I run node.js Express in production mode via sudo? - node.js

I'm using the npm package express version 2.5.2 with node version .0.6.5. I appear to be running bash version 4.1.5 on Debian 4.4.5.
I'm trying to run my server in production mode but it still runs in development mode.
I run these commands in my bash shell:
$ export NODE_ENV=production
$ echo $NODE_ENV
production
$ sudo echo $NODE_ENV
production
$ sudo node bootstrap.js
I have this code inside bootstrap.js:
var bootstrap_app = module.exports = express.createServer();
//...
console.log(bootstrap_app.settings.env);
and here's what I see printed to standard out:
development
Is this a problem with my usage, or my system?
EDIT:
Thanks to ThiefMaster for his properly identifying that this issue stems from my running node as root. ThiefMaster suggested using iptables to forward from port 80 to an unprivileged port, but my system gives me an error. Moving this discussion to superuser.com or serverfault.com (link to follow)

Most environment variables are unset when using sudo for security reasons. So you cannot pass that environment variable to node without modifying your sudoers file to allow that variable to passt through.
However, you shouldn't run node as root anyway. So here's a good workaround:
If you just need it for port 80, run node on an unprivileged port and setup an iptables forward to map port 80 to that port:
iptables -A PREROUTING -d 1.2.3.4/32 -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 2.3.4.5:1234
Replace 1.2.3.4 with your public IP, 2.3.4.5 with the IP node runs on (could be the public one or 127.0.0.1) and 1234 with the port node runs on.
With a sufficiently recent kernel that has capability support you could also grant the node executable the CAP_NET_BIND_SERVICE privilege using the following command as root:
setcap 'cap_net_bind_service=+ep' /usr/bin/node
Note that this will allow any user on your system to open privileged ports using node!

sudo NODE_ENV=production /usr/local/bin/node /usr/local/apps/test/app.js

Related

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.

semanage command is not found in Centos 5.4

I am using the Centos 5.4.
I want to run this command without quotes to allow selinux ports for http traffic.
"semanage port -m -t http_port_t -p tcp 7000"
but error occur (semanage command is not found).
semanage is also available in this directory /usr/sbin/semanage in my OS.I already install and update the policycoreutils-1.33.12-14.13.el5.x86_64.rpm package and already try the many solutions available on internet for this problem.
How do I resolve this problem?
I resolve the issue when I try this command
/usr/sbin/semanage port -m -t http_port_t -p tcp 7000

Git hooks may need higher privileges

I'm using node.js for my webserver, and I would like forever (or something like it) to run the server.
I'm also using git to manage the website. I have a bare repository on the server that I can push to/pull from on my local machine. I would like the repository to do three things when I push to it.
CD to my working directory (on the server)
Have the working directory pull from the bare repo
Restart the running webserver.
The following script seems like it's what I should use as a post-receive hook in my bare repo.
cd ~/site
git pull
sudo forever stopall
sudo forever start main.js
However, I don't think it's smart to have the git hook use sudo like that. The script needs elevated to run on port 80.
How should I be doing this? What should my git post-receive look like?
Thanks!
Well, for my particular case, it turns out I shouldn't be running node as a super user for security reasons. I wanted it to be elevated to run on port 80, but it didn't need to be elevated to run on port 8000.
So I forwarded port 80 to port 8000, and now am running node on port 8000. It still works identically to how it did before.
The command that I used in particular to forward port 80 to 8000 is
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8000

How to run node.js as non-root user?

I'm running a node.js server, that will serve requests on port 80 amongst others. Clearly this requires the application running as root (on Linux).
Looking at this post (http://syskall.com/dont-run-node-dot-js-as-root) as an example it's clear that there are simple ways to allow node to be run as a non-root user, but I'm wondering if anyone has views on the advantages/disadvantages of the different methods suggested:
code: use setuid() to drop down from root to non-priviledged user after listening on port 80 is established.
using a proxy server of some sort to redirect requests to a port >1024 (and so not need node to run as root)
using IP tables to forward to another port (ditto node would not run as root)
Thanks
Option 1 requires you launch the node server as root. Not ideal.
Option 2 adds overhead to every handled request and adds another failure point to your stack.
Option 3 Is the simplest and most efficient method.
To implement Option 3, add the following to your system init scripts. (/etc/rc.d/rc.local on RedHat based systems like AWS).
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000
That will redirect requests from port 80 to port 3000.
(I haven't got enough reputation to add a comment the the one of Matt Browne, so I write this as an answer. Feel free to edit.)
There is a simpler method to load iptables rules automatically after a reboot than the one described in the link of Matt Browne: One can install iptables-persistent from the repositories using apt-get:
apt-get install iptables-persistent
Rules still need to be saved manually like this:
IPv4:
iptables-save > /etc/iptables/rules.v4
IPv6:
iptables-save > /etc/iptables/rules.v6
(Source: http://www.thomas-krenn.com/de/wiki/Iptables_Firewall_Regeln_dauerhaft_speichern (german))
I love the simplicity of this workaround:
sudo setcap 'cap_net_bind_service=+ep' `which node`
It also works for programs other than nodejs btw.
Basically as 2nd parameter you type the path to the program executable (like /usr/bin/nodejs on Ubuntu), in the above case which node should provide it dynamically, thus making this work independently from Linux distro.
Beware though that when you upgrade nodejs or the executable gets overwritten for some other reason you would have to execute that same command again.
Sources:
How to: Allow Node to bind to port 80 without sudo,
Is there a way for non-root processes to bind to "privileged" ports on Linux?

Setting up process.env variables using EXPORT while running node with sudo

I'm using node.js on EC2
I type
EXPORT PORT=80
in terminal, and i see that it correctly saves it when i type EXPORT
But when I run my node.js app with the following:
...
console.log(process.env);
...
PORT is not listed in the object when I'm running it with sudo:
sudo node app.js
How do I set PORT so that I can access it from the process.env object while running node with sudo?
To set process.env variable use the following code:
sudo PORT=80 node server.js
Of course, you can set multiple process.env variables:
sudo PORT=80 HOST=localhost node server.js
Normally, EXPORT should work too. But sudo creates its own environments and then starts your program as root. So, you shall either add PORT to sudo's environment or force it to preserve your own environment.
To change sudo's environment you shall modify /root/.profile.
To force it to preserve your own environment use -E key:
sudo -E node app.js
I know it is an old post but I have the same permission problem running node.js on port 80. I made a workaround to avoid running with sudo and having to define the PORT in node run command (sudo PORT=80 node server.js). What I did was redirect the traffic for the PORT 80 to another allowed port, in my case 3000.
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000
you can use cross-env to set up env and add to your scripts.
eg.
scripts: {
"build": "cross-env PORT=3000 <any_command>"
}
You can also set multiple variables .
eg.
scripts: {
"build": "cross-env PORT=3000 NODE_ENV=production <any_command>"
}
Process this using process.env.PORT and process.env.NODE_ENV

Resources