I have some NodeJS scripts, that runs 24/7 on a windows vServer. Normally I connect via RDM/VNC, open a console, navigate to the path of the script and type in "node ." to start it.
Sometimes I need to check the output of that scripts and sometimes I want to restart them.
Then I connect again to the server, check the shell, abort the process and restart it with "node ." again.
But now I want some other people to do that too but I dont want to give them access to my server.
So my plan was to do a "Managing website".
But atm I have no idea how to do it. I have several problems: First, How can I start the script with "node ." in php? I tried several stuff with the exec and shell_exec command. One example:
echo shell_exec('cd C:\\Users\***\\');
echo shell_exec("node .");
But I dont even get an output back. So obviously there is something wrong.
Second, every user of that website should see the same output. If someone hits the "Restart" Button (need to figure out a way how to restart it too), it should restart the same process some one else started earlier.
Any idea/way to go?
Here's a possible way to handle this issue.
First, package your nodejs program as a Windows Service. Here are some suggestions about how to do that. It's not hard. How to install node.js as windows service?
Then you, or anybody else, can use these command from an elevated-priv cmd.exe or powershell, to stop and start the service.
sc.exe stop yourServiceName
sc.exe start yourServiceName
If they're on another machine and they have appropriate permissions they can do
sc.exe \\YourMachineName stop yourServiceName
sc.exe \\YourMachineName start yourServiceName
Services are also handy because you can configure them to restart if they crash. And you can configure them to start automatically when the server starts up.
Related
I am trying to start a php (under apache) process (by calling the apache from a browser), that will survive shutting down the apache server (sudo service apache2 stop). Even when I make sure the created process has no parent (parent 1), and has its own session, still, somehow, the process is died when I stop the apache (or restart the apache)
I created a test.php file:
<?php
exec('setsid nohup sleep 1000 > /dev/null 2>/dev/null &');
?>
When running doing HTTP GET to this test.php, indeed we get an immediate OK response, and the process still lives.
But, when we do:
sudo service apache2 stop
The sleep process dies.
How can someone kill a process when the process doesn't belong to its group or session, and when the process is not a child?
Apache will probably have a list of the spawned processes and kills them individually, and not as a group. In that case, all processes in the list will be kill(2)ed. But see below next paragraph for a possibility.
Look at the man pages for the kill(2) system call. In the ERRORS section, the only possibilities to fail are:
EINVAL, meaning an invalid signal number has been passed. Doesn't apply here.
ESRCH, the process (or process group) doesn't exist. Doesn't apply also.
EPERM, you don't have permission to send a signal. This applies here, but the only processes (and this has nothing to do with process hierarchies or parental relationships) you are allowed to send signals to are the processes that run with real/saved user id equals the effective user id of the sender process. So, as Apache has a registry of all the processes it launches, it is normal that it is able to kill the process.
Anyway, have you tried to create a process, from that process create a subprocess, and execute the setsid in the grandchild subprocess? That way, there's no chance for the Apache process to have it registered in the list of spawned processes. I have not tried that, but it could work.
From the FreeBSD kill(2) manual page:
For a process to have permission to send a signal to a process designated
by pid, the user must be the super-user, or the real or saved user ID of
the receiving process must match the real or effective user ID of the
sending process. A single exception is the signal SIGCONT, which may
always be sent to any process with the same session ID as the sender.
(emphasis is mine) in linux, it's almost the same, except
... (if the sending process) have the CAP_KILL capability in the user namespace of the target process...
but this doesn't apply here.
I'm curious on why the apache server needs to be shut down, but im inclined to say you might try a different strategy altogether using a containerized solution. Exposing an nginx docker container that can trigger your php process would likely be more stable than using Apache, as the docker daemon always runs as root. I think it depends on the specific needs of your use case though, so explaining why you need to shut down Apache might get you better answers.
List all active processes (e.g. ps aux). The processes, which were created by Apache run as user www-data.
When you stop Apache service, I suspect they will be terminated based on that or some internal list. apache2.service stop calls apachectl -k graceful-stop. This will SIGTERM all "child processes". Unfortunately, I was unable to find the exact place in the code. Maybe someone could do that to verify the hypothesis.
A solution:
Run the process as another user. How you go about that depends on your case. You will have to define some kind of interface.
For example, you could have another process listen on localhost or use a Unix domain socket. The same will be achieved by using gearman, as #Akshay Vanjare pointed out in the comments.
Your PHP script can then call to the interface.
No solutions:
It is a bad idea to control a daemon this way, see this answer.
As user www-data you cannot start a process as another password protected user, because su asks for pass and switching UID is not a good idea.
For testing, I set up a user with empty password and used su - NEW_USER -c "COMMAND" in PHP script. Do not do this in any system you care about. It is insecure. Very insecure. And you will have a new process every time the script is called. You would have to take care to kill it.
Further thoughts:
I also tried a few alternatives to "nohup" the command, such as daemonizing, fork(), disown etc. They did not work for me.
I did not try hard in the new process to ignore SIGTERM. maybe it is possible to solve the question that way, too.
To me, it makes sense for Apache to do (aggressive) clean up when it is stopped. It is behavior I would expect from a web browser, which has to handle a lot of children.
First about my answer, it's not a good idea to control dameon from the web.
Once this said, you can have a php script that write a flag or somthing like that either on a database, a file, redis, etc.
On the other side make a PHP script that you schedule with cron for looking for the flag. If found, the script can start a PHP daemon that will detach. Pay attention to running the cron script and the PHP daemon with secured user & rights.
But once again be carefull with security concern.
From the PHP developer perspective I don't think there is a way to achieve that.
Or you can implement a queue and worker to do your tasks/executions.
and for that you can either use Redis or any other database.
https://laravel.com/docs/9.x/queues
You can write a service that then you can control with sudo service start|stop|restart
You can use visudo to edit sudoers file to allow www-data to use sudo to run a specific sh file, without being prompted by password. This sh file will contain the line service your_service start.
Example: I wanted to be able to restart apache2 from a client side ajax request.
Context: file server with no screen/keyboard attached. I have SSH setup, but I don't want to launch a client in my laptop. I protect the restart page with apache password protected directory, along with other administrative pages. For example: I have a page to restart/shutdown the whole system.
I did this:
Register a service to run with sudo service apache_restarter_service start
This service file calls a simple sh script, a two lines script: sleep 1 second and then call service apache2 restart.
Use visudo to edit sudoers file. Allow user www-data to use sudo to run a sh script that calls service apache_restarter_service start.
The service file is used only to start a process with root privileges, and it doesn't need to be long lived, so no need for Restart=always in service definition. This process cannot be killed by apache and apache won't even know about it. It will only know that the sh script returned 0.
Example of changes to sudoers file:
www-data ALL=(ALL) NOPASSWD:/opt/apache_restarter/from_php.sh
from_php.sh only calls service apache_restarter_service start. No need for sudo here, because your php script already used sudo when calling from_php.sh.
from_php.sh is needed here, because you don't want php to call service directly. Because a BUG in, or an ATTACK against, your script may do harm to your server. This way, we only authorized from_php.sh in sudoers.
The php script must call from_php.sh with sudo. You can use exec("sudo /opt/apache_restarter/from_php.sh"). An & at the end is not needed, because apache won't be restarted immediately.
Example of service definition file apache_restarter_service.service:
[Unit]
Description=Apache restarter one shot
After=multi-user.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=no
User=root
ExecStart=/opt/apache_restarter/run.sh
[Install]
WantedBy=multi-user.target
To avoid the service to run once the system is restarter. No harm really, but also useless. You can have the service always disabled and enable it in from.php script before starting it. Or just tune the service file to not run one time at system start.
You can tune StartLimitIntervalSec=0 to your needs.
You can tune User=root to a safer, less privileged user. In my case I don't care but maybe you do. You may want to use www-data. I don't know why that may not work, but I didn't tried to use www-data so far.
You can write run.sh in many ways and to do different tasks. The simpler of which would be to simply wait 1 second and then restart apache with service apache2 restart.
While my interest is to be able to restart apache from client side, this also applies to spawn a process that won't be terminated when apache is stopped/restarted.
I also tried with nohup, &, setsid and whatnot. I will save people some time. Nothing works. Apache should be terminating all child processes as already suggested.
Update 2022-12-04
I got into the following situation: need to start a python3 web server into alternate port to provide file server statistics.
Why? This is the concept, if nobody interested in the statistics (iostat, ifstat, etc) then the stats_server.py is not even running (wasting RAM/CPU). So, having stats_server.py starting with system is overkill.
Once a user visit http://FILE_SERVER_IP/stats_launch.php, or from JavaScript fetch, the program stats_server.py must be launched and listen in http://FILE_SERVER_IP:ALTERNATE_PORT. You may also need to handle CORS headers to be able to fetch from the alternate port.
Also, it keep running and updating the stats with a second, or half second, interval, and saving to its own memory, so it can calculate averages or rates per second. Doing this server side gives more precision and less latency that just send the raw samples to client side.
This URL can be visited directly (you will see the output of iostat and ifstat, and values calculated by the python script, in plain text format), or user can load FILE_SERVER_IP/stats.html, where a fetch from JavaScript will periodically load that text plain output, and parse into nice HTML/CSS.
You may think that everything can be solved by fork or by using os.getpid(), os.getsid() and os.setsid() inside the python script, to detach it from the original session and avoid termination with parent process (search stackoverflow for use cases) and it will if your www-data user has the right permissions.
Otherwise I still recommend the visudo approach above. You still need to detach if you start your python file from a .sh file, the difference is that now you have the permissions to do so.
Is there a way to run a command/method when Apache is about to exit?
I have an application running in windows with Xampp (local use only), and want to make some kind of cleanup method when this application is ended by the user, which happens when Apache's stop button is pushed.
So any kind of event fired by Xampp or apache, or even php that I can use?
And the command can be from cmd, php, whatever.
OBS: must be something before apache's closed, so check windows
process list isn't an option.
IMO, I would suggest you make a batch file that do stop Apache and call your cleaning command before or after stopping command.
This way the batch file is independent from XAMPP in case of re-installation or changing environment.
The step to reach the goal:
Run cmd as administrator
Go to your XAMPP Apache bin folder
Install Apache as service, httpd -k install
Now you should be able to manually start and stop Apache by command line
httpd -k stop
httpd -k start
You can learn more commands, check the link
Now make a batch file call it any thing you like, that do cleaning job and put it before or after you stop or start Apache
Example for testing cleanandstopapache.bat:
clean.bat // or what ever calling cleaning command.
pause // just to test pause
httpd -k stop // stops Apache
Notes:
Normally you start and stop your XAMPP via GUI. Using service has the same effect the only different is, that you gone use command line to start and stop your Apache, that said you can put any script before stop Apache to do the job.
You can either use XAMPP GUI or XAMPP services, not both.
I have test it on my machine and it works.
It is possible to give the service a unique customized name so you can see it in Windows Services.
You can inspire by an answer that it works fine for this stackoverflow question "Run PHP script in background on Apache start/restart(Windows Server)"
Here the link of my solution
In your case, you must replace
%APACHE_HOME%\bin\httpdVendor.exe -k runservice
by
%APACHE_HOME%\bin\httpdVendor.exe -k stopservice
I didn't test this case, and i hope that it will help you
Do not hesitate to ask me questions on your needs :)
Good luck :)
There is a HUGE difference between application-end and Apache-end. Which one do you mean?
If you need a clean shutdown during but at the end of your Application, use a __deconstruct() method in the appripriate class.
If you need a step further in time, use a combination of ignore_user_abort() and register_shutdown_function().
If you mean Apache stopping, you should search for a script or tool that watches the process list and acts when the Apache process is not in this list.
I need to keep a php script running and alive on my server, the script runs and checks a DB for record, processes if needed, sleeps for 3 and then loops to the top of the script in an infinite loop. The issue is launching it, if I launch it via terminal (its running on an ubuntu system) using php script.php then if the terminal session is ended the script stops running.
So how can I go about launching the script so that it will remain running in the background.
Furthermore if I set up a cron job that runs once an hour and fires off a different script that check the primary one is still running and if not restarts it, how would I get the this checker script to check that the initial script is still running (even if its in sleep).
Any assistance will be greatly appreciated
If starting the script from the web is an option, then set time limit to "unlimited" (in the script itself):
set_time_limit(0);
and set ignore_user_abort to "true":
ignore_user_abort(true);
Then you can run the script as usual from the web, and it will run forever (until the process is killed or script exits in the usual way).
Of course, you can (and MUST) protect such a starter-script by password, e.g. by using HTTP authentication via .htaccess, so that somebody cannot start many forever-running scripts, which would lay down your server.
On checking whether another process is running, see question1, question2, or try searching "[php] check if process is running" here on StackOverflow. See also http://php.net/manual/en/refs.fileprocess.process.php.
If you want to run it from the terminal and keep it running permanently, look into GNU screen. It's a virtual terminal that keeps running in the background even when you close the terminal.
$ sudo apt-get install screen
With this, you can simply do:
$ screen php myscript.php
The script will load in a screen session which you can disconnect from, and even when you close the terminal it will keep running. To check up on it, simply call:
$ screen -x
Best part is screen is free software and is in the repo of all good distros (and other *NIX's if Linux doesn't float your boat).
Cron Job would be one solution:
More details about Cron job.
Another way to do it is to use Gearman or some other taks managers like in this post
I have two problems which are related.
1) I have a batch file that contains this:
net stop wampapache
net start wampapache
Which tries to stop and start my wamp server. When I double click the stop.bat file with the above it works successfully. When I try to run that from my PHP script, it stops the server but doesn't start it fully which I am guessing is because Apache is waiting for that PHP process to exit?
function php_kill(){
exec('stop.bat', $output = array(), $return);
return $return;
}
2) Is there a way to restart my webserver (apache) whilst keeping session variables that PHP needs available?
Thanks all
The PHP process is killing a process that, in turn, kills the PHP process. It's like going back in time and murdering your parents before they gave birth to you. I don't see how it can work.
One has to ask why this functionality is necessary. If you must do it this way, you should look into scheduling a service restart from the script. I don't know if this is possible via PHP and Windows.
The problem is related to the fact that exec waits for the process to end, but the process actually kills PHP so the whole thing gets stuck.
Running stop.bat as a background process should fix it. (here how to run a background process on Windows)
I need an application to be running in the background on my web server, but I need to be able to start/stop the application with root privileges.
In order to do this, I want to have a service running that has root privileges, so that it can kill the application, and start it up again if need be.
Finally, I need to be able to send the start and kill commands to the service via Apache/PHP, so that it can be indirectly controlled through the web.
How do I create a Linux service?
How do I communicate with a Linux service in this manner?
Thanks in advance!
Use the exec command in your PHP script to call shell files. The shell files can be setup with the "setuser" bit so it will run as its owner (instead of running with the web server's permissions).
Of course, you'll need to be very careful--lots of testing, monitoring, etc.
Finally, think about the service running as a dedicated user, not as root. Eg like apache and most other well done services do.
Added: Re: running a service in Linux. Depends on your flavor of Linux. If you want to be sure that your app service will be automatically re-started if it fails, plus logging, checkout Runit:
https://web.archive.org/web/1/http://blogs.techrepublic%2ecom%2ecom/opensource/?p=202
http://smarden.org/runit
Added: Instead of setuid bit, I think Frank's suggestion (in comment) of using sudo system is better.
So, you have three pieces here :
Your web server without root privilege
An application
A daemon that is monitoring the application
Your problem is not launching the daemon, it is writing it, and communicating with it from the web server, without needing root privilege.
A daemon can be as simple as a non interactive application launched in the background :
# my_dameon &
I am not a php developper, but searching for message queue and php, I discovered beanstalkd
Looking at the example on the first page it seems you can use it to do the following :
The apache/php sends some message to beanstalkd
Your daemon reads the message from beanstalkd. Based on the command it starts or kill or reload the background application.
You can write your daemon in php, since there are client in many languages
You can also check this question
You can create a daemon which accepts the following commands:
daemon_name start
daemon_name stop
daemon_name restart
deamon_name reload
Starting the daemon should not be hard. Just executing daemon_name start from a PHP script should run it. After starting, you can write the PID of the process to a lock file (for stopping, restarting or reloading later). The daemon should handle signals.
In a PHP script, you can then invoke daemon_name stop. This should fire up a new daemon which would check the lock file and get the PID of the running daemon and send a signal which would be handled by the running daemon. The lock file should be removed/cleared and then the stop initiating daemon/process can quit.
I think you should look at inetd, which can be configured to run all sorts of services, and it runs as root. You could then write a relatively simple program that is not itself root privileged, but which when run by root does the tasks you need done.
As far as communicating with the service you did not say what type of service it is, however assuming you're writing it yourself the most common methods would be to comunicate via UNIX sockets or MMAP. Depends on your needs really.
Oh yeah, should point out there are already applications for web management of linux systems. Webmin is a really good one which can be configured to allow as much or as little control as you need.
As #shodanex suggests, using Beanstalkd would be an excellent way to disconnect a web-front-end from a running-as-root command line worker. It could trivially be set to only run exactly what was required.
To run the worker, Pear's System_Daemon can generate and run a daemon-running script, with start/stop/restart.
When doing this be very very careful. Never use any user submitted data from the web in the exec command. this could allow someone to arbitrarily execute commands on your machine.
Also I second Frank use a sudo rule so you can run that specific command with the permissions you need but nothing else. It will be more secure that way.
Of course with
sudo apt-get install openbsd-inetd
you can create a service you want