I'm attempting to construct a monitoring webservice using docker & PHP
I have a PHP script that when accessed performs a check to see if a number of services are running (through checking the HTTP headers for the services enpoints).
I have a functions.inc.php file and an index.php file
Here is my index.php file
<?php
header("Access-Control-Allow-Origin: *");
header("Content-type: application/json");
require('functions.inc.php');
//connect to MySQL DB
include("conn.php");
//Log file - check if it exists - create one if not
$file = "/var/www/html/logs/log".date("Y-m-d").".txt";
if (!file_exists($file)){
echo "Log file for today does not exist... creating and writing logfile\n";
$logdata = "Monitoring log for: ".date("Y/m/d"."\n");
file_put_contents($file,$logdata,FILE_APPEND);
}else{
echo "Log file for today exists\n";
}
//service.csv can be configured to add
//or remove services to the monitoring
//Open service config csv
//Check if service.CSV is openable
$services = fopen("/var/www/html/service.CSV",'r');
if($services){
//Read first line
fgetcsv($services,1000,',');
//loop through each service - perform check and write result to file
while(($value = fgetcsv($services,1000,','))!== FALSE){
$service=$value[0];
if(servicecheck($service)){
$response = "[".$service." - is running]\n";
}else{
$response = "[".$service." - is not running]\n";
}
echo $response;
file_put_contents($file,date("[h:i:sa ")."]".$response,FILE_APPEND);
}
}else{
die("Unable to open file");
}
I can currently run the script through buidling and running it through docker, making it accessible through localhost port 80.
Here is my initial Dockerfile:
FROM php:7.2-apache
COPY src/ /var/www/html/
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
RUN chmod 777 /var/www/html
This all works as intended. I can access the service through localhost:80 on my browser.
However, I want these service checks to run even when the page isn't accessed.
I found that cron would be the appropriate solution for this, and I tried to implement it. My new dockerfile looks like this-
FROM php:7.2-apache
COPY src/ /var/www/html/
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
RUN chmod 777 /var/www/html
RUN apt-get update && apt-get -y install cron
# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron
# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron
# Apply cron job
RUN crontab /etc/cron.d/hello-cron
RUN chmod 777 /etc/cron.d/hello-cron
RUN touch /var/log/cron.log
CMD cron && tail -f /var/log/cron.log
This does work. In the docker terminal I can see the script running every minute. It outputs to terminal what until now has been output to the browser. However now I can't access it through localhost:80 and make the php script run manually.
heres my cronfile (hello-cron) for reference
* * * * * /usr/local/bin/php /var/www/html/index.php >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.
I believe the issue lies with cron, as its the final line CMD cron && tail -f /var/log/cron.log that makes the page inaccessible.
Is there any solution for this? I'm relatively new to it all so I'm sure there is something I'm missing but I cant find anything that helps
Related
I have a file upload form and after the file uploads I want to push the files up to GitHub by running:
git add .
git commit -m "some message"
git push origin master
How do I go about this? I've seen examples of using exec() but that makes me nervous.
shell_exec('cd /var/www/vhost/xxx.com/httpdocs/clients/portal/upoads/54 && /usr/bin/git add -A');
shell_exec('cd /var/www/vhost/xxx.com/httpdocs/clients/portal/upoads/54 && /usr/bin/git commit -m "something 1"');
shell_exec('cd /var/www/vhost/xxx.com/httpdocs/clients/portal/upoads/54 && /usr/bin/git push origin master');
Those commands don't error but don't work either. Do I need to grant access to the apache user to use the ssh key?
i guess is permission problems, you can use exec() , and get the error info by $output
exec($your_command.' 2>&1', $output, $return_var);
var_dump($output);
Do I need to grant access to the apache user to use the ssh key?
Yes.
This means you have to copy the key somewhere that the apache user can read it. SSH won't work unless the key file is readable by the user only (i.e. 0600 permissions on the key file).
Copy the key like:
mkdir -p --mode=0700 ~apache/.ssh
cp /my/id_rsa ~apache/.ssh/id_rsa
chown -R apache:apache ~apache/.ssh/id_rsa
chmod 0600 ~apache/.ssh/id_rsa
Also, you don't need to cd every time you want to run the command. Use GIT_DIR:
putenv('GIT_DIR=/path/to/git/repo')
shell_exec('git commit ...')
I solved it. I ran all of this as root user.
Inside my PHP script I ran
exec("whoami");
to get the user that is running that script. Then I ran
cat /etc/passwd
to get the home directory for that user (/var/www/vhost/mydomain.com)
I noticed that on my web server (Centos 7) that all my web files were chown'd as opcode:psacln so I created a .ssh directory inside opcode's home folder:
mkdir -p --mode=0700 /var/www/vhost/mydomain.com/.ssh
cd (back to root)
cp .ssh/id_rsa /var/www/vhost/mydomain.com/.ssh/id_rsa
chown -R opcode:psacln /var/www/vhost/mydomain.com/.ssh/id_rsa
chmod 0600 /var/www/vhost/mydomain.com/.ssh/id_rsa
The thing I was missing was that I had to also move my known_hosts file over, since the script I was using wasn't adding to it.
cp .ssh/known_hosts /var/www/vhost/mydomain.com/.ssh/known_hosts
chmod 0600 /var/www/vhost/mydomain.com/.ssh/known_hosts
Of course, I had to login to my server at the command line and do an initial commit to the repo in order to get it added to my known_hosts file, before I copied it over. Hope this helps someone.
I simply want to restart named depending on whether a file exists. I've been stuck on this all day.
Command to create bash file:
$this->execute('echo -e "#!/bin/bash\nsudo /sbin/service named reload" >> /var/reload_named.sh');
Here is my cronjob:
*/1 * * * * cronjob: sudo sh /var/reload_named.sh; rm -f /var/reload_named.sh;
Here is what happens when the cronjob runs (/var/log/cron):
Jul 30 18:34:01 digitalocean CROND[24864]: (root) CMD (cronjob: sudo sh /var/reload_named.sh; rm -f /var/reload_named.sh )
Jul 30 18:34:01 digitalocean CROND[24862]: (root) UNSAFE (”example#digitalocean.com”)
For some reason it says it is UNSAFE. I've tried running with and without sudo.
It manages to delete the file but not restart named. I have tried doing so many other methods to get this to work.
I've tried (Over lots of Googling):
Running exec('service named restart') in php
Creating a .c file and adding a user that runs it from php
Running service named restart directly in crontab -e
Attempted different variations on running it with sudo
Tried adding apache user to sudo (Still fails)
Any help much appeciated
(I am on Centos 6.7)
I finally worked out a way to do this. Here is a method which SSHs into itself as root and runs service command:
$this->root_execute('service named reload');
public function root_execute($command = '')
{
set_include_path('/path/to/dir/ssh/');
require_once('Net/SSH2.php');
$ssh = new Net_SSH2(SSH_HOST);
if (!$ssh->login(SSH_USER, SSH_PASS)) {
exit('failed');
}
$res = $ssh->exec($command);
$ssh = null;
restore_include_path();
return $res;
}
(Unfortunately doesn't work with HTTPD if running from http .php)
I want to execute a Bash script present on the system from a PHP script. I have two scripts present on the system. One of them is a PHP script called client.php present at /var/www/html and the other is a Bash script called testscript present at /home/testuser.
My client.php script looks like
<?php
$message=shell_exec("/home/testuser/testscript 2>&1");
print_r($message);
?>
My testscript looks like
#!/bin/bash
echo "Testscript run succesful"
When i do the following on terminal
php client.php
I get the following output on terminal
Testscript run successful
But when i open the page at
http://serverdomain/client.php
I get the following output
sh: /home/testuser/testscript: Permission denied
I get this error even after I did chmod +x testscript.
How do I get it to work from the browser? Please help.
I would have a directory somewhere called scripts under the WWW folder so that it's not reachable from the web but is reachable by PHP.
e.g. /var/www/scripts/testscript
Make sure the user/group for your testscript is the same as your webfiles. For instance if your client.php is owned by apache:apache, change the bash script to the same user/group using chown. You can find out what your client.php and web files are owned by doing ls -al.
Then run
<?php
$message=shell_exec("/var/www/scripts/testscript 2>&1");
print_r($message);
?>
EDIT:
If you really want to run a file as root from a webserver you can try this binary wrapper below. Check out this solution for the same thing you want to do.
Execute root commands via PHP
Without really knowing the complexity of the setup, I like the sudo route.
First, you must configure sudo to permit your webserver to sudo run the given command as root. Then, you need to have the script that the webserver shell_exec's(testscript) run the command with sudo.
For A Debian box with Apache and sudo:
Configure sudo:
As root, run the following to edit a new/dedicated configuration file for sudo:
visudo -f /etc/sudoers.d/Webserver
(or whatever you want to call your file in /etc/sudoers.d/)
Add the following to the file:
www-data ALL = (root) NOPASSWD: <executable_file_path>
where <executable_file_path> is the command that you need to be able to run as root with the full path in its name(say /bin/chown for the chown executable). If the executable will be run with the same arguments every time, you can add its arguments right after the executable file's name to further restrict its use.
For example, say we always want to copy the same file in the /root/ directory, we would write the following:
www-data ALL = (root) NOPASSWD: /bin/cp /root/test1 /root/test2
Modify the script(testscript):
Edit your script such that sudo appears before the command that requires root privileges(say sudo /bin/chown ... or sudo /bin/cp /root/test1 /root/test2). Make sure that the arguments specified in the sudo configuration file exactly match the arguments used with the executable in this file.
So, for our example above, we would have the following in the script:
sudo /bin/cp /root/test1 /root/test2
If you are still getting permission denied, the script file and it's parent directories' permissions may not allow the webserver to execute the script itself.
Thus, you need to move the script to a more appropriate directory and/or change the script and parent directory's permissions to allow execution by www-data(user or group), which is beyond the scope of this tutorial.
Keep in mind:
When configuring sudo, the objective is to permit the command in it's most restricted form. For example, instead of permitting the general use of the cp command, you only allow the cp command if the arguments are, say, /root/test1 /root/test2. This means that cp's arguments(and cp's functionality cannot be altered).
I was struggling with this exact issue for three days. I had set permissions on the script to 755. I had been calling my script as follows.
<?php
$outcome = shell_exec('/tmp/clearUp.sh');
echo $outcome;
?>
My script was as follows.
#!bin/bash
find . -maxdepth 1 -name "search*.csv" -mmin +0 -exec rm {} \;
I was getting no output or feedback. The change I made to get the script to run was to add a cd to tmp inside the script:
#!bin/bash
cd /tmp;
find . -maxdepth 1 -name "search*.csv" -mmin +0 -exec rm {} \;
This was more by luck than judgement but it is now working perfectly. I hope this helps.
It's a simple problem. When you are running from terminal, you are running the php file from terminal as a privileged user. When you go to the php from your web browser, the php script is being run as the web server user which does not have permissions to execute files in your home directory. In Ubuntu, the www-data user is the apache web server user. If you're on ubuntu you would have to do the following:
chown yourusername:www-data /home/testuser/testscript
chmod g+x /home/testuser/testscript
what the above does is transfers user ownership of the file to you, and gives the webserver group ownership of it. the next command gives the group executable permission to the file. Now the next time you go ahead and do it from the browser, it should work.
I want to execute a Bash script present on the system from a PHP script. I have two scripts present on the system. One of them is a PHP script called client.php present at /var/www/html and the other is a Bash script called testscript present at /home/testuser.
My client.php script looks like
<?php
$message=shell_exec("/home/testuser/testscript 2>&1");
print_r($message);
?>
My testscript looks like
#!/bin/bash
echo "Testscript run succesful"
When i do the following on terminal
php client.php
I get the following output on terminal
Testscript run successful
But when i open the page at
http://serverdomain/client.php
I get the following output
sh: /home/testuser/testscript: Permission denied
I get this error even after I did chmod +x testscript.
How do I get it to work from the browser? Please help.
I would have a directory somewhere called scripts under the WWW folder so that it's not reachable from the web but is reachable by PHP.
e.g. /var/www/scripts/testscript
Make sure the user/group for your testscript is the same as your webfiles. For instance if your client.php is owned by apache:apache, change the bash script to the same user/group using chown. You can find out what your client.php and web files are owned by doing ls -al.
Then run
<?php
$message=shell_exec("/var/www/scripts/testscript 2>&1");
print_r($message);
?>
EDIT:
If you really want to run a file as root from a webserver you can try this binary wrapper below. Check out this solution for the same thing you want to do.
Execute root commands via PHP
Without really knowing the complexity of the setup, I like the sudo route.
First, you must configure sudo to permit your webserver to sudo run the given command as root. Then, you need to have the script that the webserver shell_exec's(testscript) run the command with sudo.
For A Debian box with Apache and sudo:
Configure sudo:
As root, run the following to edit a new/dedicated configuration file for sudo:
visudo -f /etc/sudoers.d/Webserver
(or whatever you want to call your file in /etc/sudoers.d/)
Add the following to the file:
www-data ALL = (root) NOPASSWD: <executable_file_path>
where <executable_file_path> is the command that you need to be able to run as root with the full path in its name(say /bin/chown for the chown executable). If the executable will be run with the same arguments every time, you can add its arguments right after the executable file's name to further restrict its use.
For example, say we always want to copy the same file in the /root/ directory, we would write the following:
www-data ALL = (root) NOPASSWD: /bin/cp /root/test1 /root/test2
Modify the script(testscript):
Edit your script such that sudo appears before the command that requires root privileges(say sudo /bin/chown ... or sudo /bin/cp /root/test1 /root/test2). Make sure that the arguments specified in the sudo configuration file exactly match the arguments used with the executable in this file.
So, for our example above, we would have the following in the script:
sudo /bin/cp /root/test1 /root/test2
If you are still getting permission denied, the script file and it's parent directories' permissions may not allow the webserver to execute the script itself.
Thus, you need to move the script to a more appropriate directory and/or change the script and parent directory's permissions to allow execution by www-data(user or group), which is beyond the scope of this tutorial.
Keep in mind:
When configuring sudo, the objective is to permit the command in it's most restricted form. For example, instead of permitting the general use of the cp command, you only allow the cp command if the arguments are, say, /root/test1 /root/test2. This means that cp's arguments(and cp's functionality cannot be altered).
I was struggling with this exact issue for three days. I had set permissions on the script to 755. I had been calling my script as follows.
<?php
$outcome = shell_exec('/tmp/clearUp.sh');
echo $outcome;
?>
My script was as follows.
#!bin/bash
find . -maxdepth 1 -name "search*.csv" -mmin +0 -exec rm {} \;
I was getting no output or feedback. The change I made to get the script to run was to add a cd to tmp inside the script:
#!bin/bash
cd /tmp;
find . -maxdepth 1 -name "search*.csv" -mmin +0 -exec rm {} \;
This was more by luck than judgement but it is now working perfectly. I hope this helps.
It's a simple problem. When you are running from terminal, you are running the php file from terminal as a privileged user. When you go to the php from your web browser, the php script is being run as the web server user which does not have permissions to execute files in your home directory. In Ubuntu, the www-data user is the apache web server user. If you're on ubuntu you would have to do the following:
chown yourusername:www-data /home/testuser/testscript
chmod g+x /home/testuser/testscript
what the above does is transfers user ownership of the file to you, and gives the webserver group ownership of it. the next command gives the group executable permission to the file. Now the next time you go ahead and do it from the browser, it should work.
I want to launch the command "unoconv" from a script php.
$command = '/usr/bin/unoconv --server localhost --port 2002 --format=pdf file.rtf >/dev/null 2>/dev/null';
$rc = system( $command );
echo $rc;
The command return no result and the file is not created.
I think is a problem from access with www-data and unoconv.
When I'm launching the command in shell, the file is created.
Any idea?
You can add command unoconv to sudoers.
I do this in this way:
I create wrapper bash script in for example /usr/local/bin where I have command unoconv.
#!/bin/bash
if [ -z "$1" ]; then
echo "Must pass file";
exit 10;
fi
/usr/bin/unoconv -f pdf $1.rtf
after this I adding entry in /etc/sudoers.d:
www-data ALL=NOPASSWD: /usr/local/bin/unoconv.sh
And now you can call script in php:
exec('sudo /usr/local/bin/unoconv.sh '.$fileName);
Try to run
$output = `/usr/bin/unoconv --server localhost --port 2002 --format=pdf file.rtf`;
instead and see error messages.
For me works like this:
$cmd = "/usr/bin/unoconv -f docx files/thefile";
shell_exec($cmd);
of course you have to do this previously (if you lounch your php script from the web):
chown -R www-data:www-data files/
I have found a solution to this problem when running Apache. You have to create the home folder for the www-data user
sudo mkdir /home/www-data
sudo chown www-data /home/www-data
Lastly we will have to edit the home directory and default shell for the www-data user
sudo vim /etc/passwd
For the entry of www-data the last two strings have to be replaced respectively with
/home/www-data
/bin/bash
Simple as this
$output = shell_exec('/opt/libreoffice5.0/program/python unoconv -f rtf test.html');
Edit the path to suite your configuration.
It just works!
You may be running into an issue with LibreOffice, OpenOffice or soffice not being able to write to the current user's $HOME directory.
By running the command below I was able to identify the correct $HOME directory and see the error that was being generated.
$cmd = 'echo $HOME & unoconv -vvvv --format %s --output %s %s 2>/tmp/unoconv.debug.txt';
exec($cmd);
The verbose output of $cmd will be generated written to the file: /tmp/unoconv.debug.txt.
In my case the output was:
Verbosity set to level 5
DEBUG: Connection type: socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;StarOffice.ComponentContext
DEBUG: Existing listener not found.
DEBUG: Launching our own listener using /usr/lib64/libreoffice/program/soffice.bin.
Failed to connect to /usr/lib64/libreoffice/program/soffice.bin (pid=32012) in 6 seconds.
Connector : couldn't connect to socket (Success)
Error: Unable to connect or start own listener. Aborting.
The command ran seemed to fine as root, and as sudo -u nobody. On seeing this output I realized there was an issue with the home directory.
Kudos to Dag Wieers for his help - I'm hoping this helps other unoconv devs with their debugging.