Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Starting FOREVER or PM2 as WWW-DATA from a PHP script

I have a nodejs script named script.js.

var util = require('util'); 
var net = require("net"); 

process.on("uncaughtException", function(e) {
console.log(e);
});

var proxyPort = "40000"; 
var serviceHost = "1.2.3.4"; 
var servicePort = "50000"; 

net.createServer(function (proxySocket) {
    var connected = false;
    var buffers = new Array();
    var serviceSocket = new net.Socket();
    serviceSocket.connect(parseInt(servicePort), serviceHost);
    serviceSocket.pipe(proxySocket).pipe(serviceSocket);
    proxySocket.on("error", function (e) {
        serviceSocket.end();
    });
    serviceSocket.on("error", function (e) {
        console.log("Could not connect to service at host "
            + serviceHost + ', port ' + servicePort);
        proxySocket.end();
    });
    proxySocket.on("close", function(had_error) {
        serviceSocket.end();
    });
    serviceSocket.on("close", function(had_error) {
        proxySocket.end();
    });
}).listen(proxyPort);

I am runing it normally like nodejs script.js, but now i want to include forever or pm2 functionalities as well. When i am root everything works smootly:

chmod -R 777 /home/nodejs/forever/;
-- give rights

watch -n 0.1 'ps ax | grep forever | grep -v grep'
-- watch forwarders (where i see if a forever is opened)

/usr/local/bin/forever -d -v --pidFile "/home/nodejs/forever/file.pid" --uid 'file' -p '/home/nodejs/forever/' -l '/home/nodejs/forever/file.log' -o '/home/nodejs/forever/file.log' -e '/home/nodejs/forever/file.log' -a start /etc/dynamic_ip/nodejs/proxy.js 41789 1.2.3.4:44481 414 file
-- open with forever

forever list
-- it is there, i can see it

forever stopall
-- kill them all

The problem is when i want to run the script from a PHP script with the system or exec functions :

sudo -u www-data /usr/local/bin/forever -d -v --pidFile "/home/nodejs/forever/file.pid" --uid 'file' -p '/home/nodejs/forever/' -l '/home/nodejs/forever/file.log' -o '/home/nodejs/forever/file.log' -e '/home/nodejs/forever/file.log' -a start /etc/dynamic_ip/nodejs/proxy.js 41789 1.2.3.4:44481 414 file
-- open as www-data (or i can do this just by accessing `http://1.2.3.4/test.php`, it is the same thing)

forever list
-- see if it is there, and it is not (i see it in watch)

forever stopall
-- says no forever is opened

kill PID_ID
-- the only way is to kill it by pid ... and on another server all of this works very well, can create and kill forevers from a php script when accessing it from web ... not know why
-- everything is in /etc/sudoers including /usr/local/bin/forever 

Why is that? How can i solve this?

I also made some trick, created a user 'forever2', i created a script.sh with this content :

sudo su forever2 user123; /usr/local/bin/forever -d -v --pidFile "/home/nodejs/forever/file.pid" --uid 'file' -p '/home/nodejs/forever/' -l '/home/nodejs/forever/file.log' -o '/home/nodejs/forever/file.log' -e '/home/nodejs/forever/file.log' -a start /etc/dynamic_ip/nodejs/proxy.js 41789 1.2.3.4:44481 414 file;

where user123 is not existent, is just a trick to exit the shell after execution. The script works, runs forever, i can close all forevers with the command forever stopall from root. When i try the same thing running the http://1.2.3.4/test.php or as www-data user i cannot close it from root or www-data, so not even this works.

I tried from Ubuntu 14.04.3 LTS, Ubuntu 14.04 LTS , Debian GNU/Linux 8 ... still the same thing.

Any ideeas?

Thanks.

like image 669
Damian Avatar asked Oct 31 '15 12:10

Damian


2 Answers

If you are starting the process from within Apache or the web-server you are already as the www-data user, so doing a sudo su to the user context you already have is likely not necessary.

When you start this forever task you may also be required to shut the terminals/inputs and directly send to background. Something like this:

// Assemble command
$cmd = '/usr/bin/forever';
$cmd.= ' -d -v --pidfile /tmp/my.pid'; // add other options
$cmd.= ' start';
$cmd.= ' /etc/dynamic_ip/nodejs/proxy.js';
// "magic" to get details
$cmd.= ' 2>&1 1>/tmp/output.log'; // Route STDERR to STDOUT; STDOUT to file
$cmd.= ' &'; // Send whole task to background.
system($cmd);

Now, there won't be any output here but you should have something in /tmp/output.log which could show why forever failed, or the script crashed.

If you've been running the script sometimes as root, then trying the same command as www-data you may also be running into a permissions on one or more files/directories created from the execution as root which now conflict when running as www-data.

like image 177
edoceo Avatar answered Nov 17 '22 20:11

edoceo


This is part of PHP security you say you're running it from a php script and your not your running it from Apache via a php script.

PHP web scripts should not have root access as such they run under the same permissions as Apache user www-data.

There are ways to prevent php running as root but run a task as root but it's a little hacky and I'm not going to share the code but I will explain so you can look into it. here is where to start

http://php.net/manual/en/function.proc-open.php

With a Proccess like this you can then execute a proc. Like your script.js via nodeJS using SUDO and then read stdOut and stdErr wait for password request then provide it by writing to stdIn for that process.

Don't forget in doing this the user www-data has to have a password and be in the sudoers list

Per the OPs Comment Due to the way SUDO works the PATH does not appear to contain the path to the node executables npm, node so your best of building a .sh (bash script) and using sudo to run that.

You still need to monitor this process as it will still ask for a password

#!/bin/bash
sudo -u ec2-user -i
# change this to the path you want to run from
cd ~
/usr/local/bin/pm2 -v 
like image 44
Barkermn01 Avatar answered Nov 17 '22 21:11

Barkermn01