Bash does not execute the certbot command, how to find out why?
When I use ls command to test normal bash functions
php:
$cmd = "/bin/bash /usr/local/openresty/nginx/html/pHpServer-PG/api/cert.bash test.com";
echo $cmd;
$ww = shell_exec($cmd);
var_dump($ww);
bash:
#!/bin/bash
certbot certonly --rsa-key-size 4096 --webroot --agree-tos --no-eff-email --email email#gmail.com -w /usr/local/openresty/nginx/html -d $1 -d admin.$1 -d www.$1
I use php-fpm and nginx with user root
Some way to extract bash error?
Do you specify the variable in -d $1 -d admin.$1 -d www.$1 port of the code, so $1?
That suggests you're passing a domain name to the code.
You can also run the bash script with bash -x, so e.g. if you named your script certificate.sh, run
bash -x certificate.sh domain.com
where domain.com is your domain name.
Related
index.php:
<?php
$host = getenv('HOST');
$port = getenv('PORT');
echo "HOST is : $host";
echo "PORT is : $port";
?>
Dockerfile:
FROM php:7.4-cli
COPY . /var/www/php
EXPOSE 8000
RUN adduser rouser
CMD ["su", "-", "rouser", "-c", "cd /var/www/php && php -S 0.0.0.0:8000"]
I build a PHP docker image for my application.
docker build -t php-web-app:1.0.0 .
Running my PHP docker container:
docker run -e HOST='0.0.0.0' \
-e PORT='8084' \
-p 8000:8000 \
php-web-app:1.0.0
I made a curl request to my web application, and here the docker environment variable is not accessible by the PHP web application. It seems to be a security feature and how to do we access the docker environmental variable within a php web application.
$ curl http://0.0.0.0:8000/
HOST is : PORT is :
I'm going to guess that changing user does not preserve the environment variables of your execution.
You can check which variables are available in the environment with the env command.
There are however several things that are non-idiomatic going on with your Dockerfile.
You should not create users in your docker image. You can simply set the userid and groupid of your user in the container by setting the --user uid:gid flag in docker run.
You should not run interactive commands such as adduser in a Dockerfile. Unless you can provide all parameters in a single command so that it can run without user-intervention. Adding users is not one of them; how will you provide a password?
So to see the the environment, change your CMD line to the following:
CMD ["su", "-", "rouser", "-c", "env"]
You will see that it prints the following:
SHELL=/bin/bash
PWD=/home/rouser
LOGNAME=rouser
HOME=/home/rouser
USER=rouser
SHLVL=0
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
MAIL=/var/mail/rouser
_=/usr/bin/env
The environment variables you set are not available. However, if we change the CMD line to just print the env we get another output.
CMD ["env"]
shows us:
HOSTNAME=be0b41fed51e
PHP_INI_DIR=/usr/local/etc/php
PORT=8084
HOME=/root
PHP_LDFLAGS=-Wl,-O1 -pie
PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_MD5=
PHP_VERSION=7.4.6
GPG_KEYS=42670A7FE4D0441C8E4632349E4FDC074A4EF02D 5A52880781F755608BF815FC910DEB46F53EA312
PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_ASC_URL=https://www.php.net/distributions/php-7.4.6.tar.xz.asc
PHP_URL=https://www.php.net/distributions/php-7.4.6.tar.xz
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOST=0.0.0.0
PHPIZE_DEPS=autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c
PWD=/
PHP_SHA256=d740322f84f63019622b9f369d64ea5ab676547d2bdcf12be77a5a4cffd06832
Notice here that the user is not rouser, but the root user. You can change this by passing, for example, --user 1000:1000 in your docker run command.
So, to fix your problem, I propose you use the following Dockerfile:
FROM php:7.4-cli
COPY . /var/www/php
EXPOSE 8000
# RUN adduser rouser
# CMD ["su", "-", "rouser", "-c", "cd /var/www/php && php -S 0.0.0.0:8000"]
WORKDIR /var/www/php
CMD ["php", "-S", "0.0.0.0:8000"]
Then we get the following output:
$ curl http://0.0.0.0:8000
HOST is : 0.0.0.0PORT is : 8084
If you login to your docker container with
docker exec -it [container id] bash
and run
env
command, you will see that the passed variables are there.
I'm not a PHP expert, but try the same exercise locally (without docker) and see if you are able to print out any env variable via getenv
I have the shell script "test.sh":
#!/system/bin/sh
PID=$(ps | grep logcat | grep root |grep -v grep | awk '{print $2}')
echo "Using awk: $PID"
PID=$(ps | grep logcat | grep root |grep -v grep | cut -d " " -f 7 )
echo "Using cut: $PID"
When I run the script from PHP:
exec("su -c sh /path/to/my/script/test.sh");
I got this output:
Using awk:
Using cut: 6512
So "cut" command is work but "awk" command doesn't when I run the script from PHP, but when I run it from terminal:
# sh test.sh
I can get both awk and cut work fine! This how look like the output of "ps":
USER PID PPID VSIZE RSS WCHAN PC NAME
root 6512 5115 3044 1108 poll_sched b6e4bb0c S logcat
Do I missed something?
You should learn how to debug first
You said
So "cut" command is work but "awk" command doesn't when I run the
script from PHP, but when I run it from terminal:
I wonder how ?
actually throws error like below, in CLI
$ php -r 'exec("su -c sh /path/to/my/script/test.sh");'
su: user /path/to/my/script/test.sh does not exist
You first need below syntax while debugging code
// basic : stdin (0) stdout (1) stderr (2)
exec('your_command 2>&1', $output, $return_status);
// to see the response from your command
// su: user /path/to/my/script/test.sh does not exist
print_r($output);
Remember :
su gives you root permissions but it does not change the PATH variable and current working directory.
The operating system assumes that, in the absence of a username, the
user wants to change to a root session, and thus the user is prompted
for the root password
[akshay#localhost Desktop]$ su
Password:
[root#localhost Desktop]# pwd
/home/akshay/Desktop
[root#localhost Desktop]# exit
exit
[akshay#localhost Desktop]$ su -
Password:
[root#localhost ~]# pwd
/root
Solution:
You should allow executing your script without password prompt ( don't use su use sudo )
To allow apache user to execute your script and some commands you may make entry like below in /etc/sudoers
# which awk => give you awk path
# same use in your script also, or else set path variable
www-data ALL=NOPASSWD: /path/to/my/script/test.sh, /bin/cut, /usr/bin/awk
So it becomes :
// assuming your script is executable
exec("sudo /path/to/my/script/test.sh 2>&1", $output);
print_r($output);
I'm trying to start a bash script later in PHP so I allowed it in visudo.
www-data ALL = (root) NOPASSWD: /sbin/iptables
www-data ALL = (root) NOPASSWD: /usr/bin/at
The script removeuserIP is just doing sudo iptables ... and is working:
#!/bin/bash
sudo iptables -t nat -D PREROUTING -s $1 -j ACCEPT;
sudo iptables -D FORWARD -s $1 -j ACCEPT;
and in the PHP code, I put this line:
$msg=exec("echo /var/www/scripts/removeuserIP $ipaddress | at now + 1 minutes");
but the issue is it's starting the script right now. I checked in /log/var/auth.log and indeed, it's starting the command right now.
I tried it in a terminal directly and there was no issue, it is starting later (with an argument of course):
echo /var/www/scripts/removeuserIP $ipaddress | at now + 1 minutes
I also tried to do it like this in a terminal but this one is not working too because it doesn't understand there is an argument for the file:
sudo at now +1 minutes -f /var/www/scripts/removeuserIP 172.24.1.115
I really don't understand why it is starting right now even if it should start 1 minute later and not now.
Would it be acceptable to put a time delay in removeuserIP script?
#!/bin/bash
sleep 1m
sudo iptables -t nat -D PREROUTING -s $1 -j ACCEPT;
sudo iptables -D FORWARD -s $1 -j ACCEPT;
Solution: Finally, after checking /var/log/apache2/error.log, I saw that it doesn't have the permission to use at.
In fact you have to go /etc/at.deny and remove the line www-date with at. There is probably a security reason for why it's forbidden by default and a better way to do this, but at least it's working.
I have a condition where I have to start iperf server as daemon on specified port and if iperf server is running, I have to send response to client. I tried
shell_exec('iperf -s -p {port} -D');
but it doesn't return control / infinite loop starts.
The server will start but the code below the shell_exec will never be executed.
Anyone has a solution or suggestion how I should approach this to get the result?
Your command iperf -s -p {port} -D happens to have stderr output, try doing this:
$outfile = "/tmp/erroutperf.out";
$port = 8080;
shell_exec("iperf -s -p $port -D > $outfile 2>&1");
basically the additional command > /tmp/erroutperf.out 2>&1, tells bash to save
both stderr output and stdout of a program (iperf) to a file /tmp/erroutperf.out
getting the output of the command is:
file_get_contents($outfile);
Currently I start an Armagetron Server with the following script
#!/bin/sh
tron="/home/duke/aa/bin/armagetronad-dedicated"
var="/home/duke/aa/servers/demo/var/"
log="${var}console_log.txt"
userconfigdir="/home/duke/aa/servers/demo/var/customize/config/"
parser="/home/duke/aa/scripts/parser.php"
ladderlog="${var}ladderlog.txt"
cmds="${var}cmd.txt"
tail -n0 -f -s 0.01 $ladderlog | $parser | $tron --userconfigdir $userconfigdir --vardir $var | tee -a $log
This runs the server and applys the php script in $parser
However, I want to start my server like this:
#!/bin/bash
screen -S $1 -X quit # avoiding to run the same server twice
screen -dmS $1 /home/duke/aa/scripts/srv $1
srv:
screen -S $1 -X logtstamp on
screen -S $1 -X logfile /home/duke/aa/servers/$1/logs
screen -S $1 -X log on
while true; do # start a loop to allow server restart if it crashes
/home/duke/aa/bin/armagetronad-dedicated --vardir /home/duke/aa/servers/$1/var --userdatadir /home/duke/aa/servers/$1/var/customize #run the server
echo "###Server has crashed. Ctrl-C to cancel reboot...###"
sleep 5
done # end the loop
the only problem here is I don't know how to specify a php parser to run on the server (im a noob). How would i modify the second scripts to allow this?
put all the code in your first block inside the while loop in the srv script, i.e.
srv:
#!/bin/bash
tron="/home/duke/aa/bin/armagetronad-dedicated"
var="/home/duke/aa/servers/demo/var/"
log="${var}console_log.txt"
userconfigdir="/home/duke/aa/servers/demo/var/customize/config/"
parser="/home/duke/aa/scripts/parser.php"
ladderlog="${var}ladderlog.txt"
cmds="${var}cmd.txt"
screen -S $1 -X logtstamp on
screen -S $1 -X logfile /home/duke/aa/servers/$1/logs
screen -S $1 -X log on
while true; do # start a loop to allow server restart if it crashes
tail -n0 -f -s 0.01 $ladderlog | $parser | $tron --userconfigdir $userconfigdir --vardir $var | tee -a $log
# /home/duke/aa/bin/armagetronad-dedicated --vardir /home/duke/aa/servers/$1/var --userdatadir /home/duke/aa/servers/$1/var/customize #run the server
echo "###Server has crashed. Ctrl-C to cancel reboot...###"
sleep 5
done # end the loop
(Does this look right?)
I hope this helps.