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.