I want to run a shell script every time my nginx server receives any HTTP request. Any simple ways to do this?
-
What is the actual problem you are trying to solve with this? As you have explained it this could easily cause more issues. – Burhan Khalid Apr 06 '14 at 07:26
-
I am on an RPi and I want one of the LEDs to blink whenever my server gets a request. – Saswat Padhi Apr 06 '14 at 07:27
-
What back end language / framework are you using? Most back end languages should allow you to call a shell script. – Chirag Bhatia - chirag64 Apr 06 '14 at 07:41
-
6My question is whether I can modify it within nginx. I don't want to call the shell script manually from PHP or any other language which I may run on every request. – Saswat Padhi Apr 06 '14 at 07:45
-
Don't forget to mark your choosed answer as accepted ;) – Stephan Oct 19 '14 at 07:52
6 Answers
You can execute a shell script via Lua
code from the nginx.conf file to achieve this. You need to have the HttpLuaModule to be able to do this.
Here's an example to do this.
location /my-website {
content_by_lua_block {
os.execute("/bin/myShellScript.sh")
}
}

- 12,022
- 7
- 56
- 67

- 4,430
- 3
- 26
- 35
-
2This seems to produce an nginx error... `[alert] 6807#0: waitpid() failed (10: No child processes)` - see http://serverfault.com/q/432609/86531 – Nick Jul 03 '15 at 22:23
-
1It seems that the standard error from `os.execute()` goes into the nginx error log, and any standard output is discarded. The `os.execute()` function returns the subprocess exit code, so this example would output an integer. Something based on `io.popen()` might work better for passing through the standard output from the subprocess. – Arto Bendiken Mar 30 '16 at 04:08
-
There is also https://github.com/juce/lua-resty-shell but that requires an external daemon. – Arto Bendiken Mar 30 '16 at 04:09
-
1Usage of [content_by_lua](https://github.com/openresty/lua-nginx-module#content_by_lua) is marked as discouraged, so I updated your answer accordingly – Arnaud P Oct 30 '17 at 08:43
-
3Can you get hold of POST or GET parameters from the request to pass the script? – Chris Dec 05 '17 at 21:46
-
Tried to install `openresty` to do so and nginx failed to start after that. Had to remove `openresty` to restart nginx – dmirg Aug 30 '23 at 16:11
I found the following information online at this address: https://www.ruby-forum.com/topic/2960191
This does expect that you have fcgiwrap installed on the machine. It is really as simple as:
sudo apt-get install fcgiwrap
Example script (Must be executable)
#!/bin/sh
# -*- coding: utf-8 -*-
NAME=`"cpuinfo"`
echo "Content-type:text/html\r\n"
echo "<html><head>"
echo "<title>$NAME</title>"
echo '<meta name="description" content="'$NAME'">'
echo '<meta name="keywords" content="'$NAME'">'
echo '<meta http-equiv="Content-type"
content="text/html;charset=UTF-8">'
echo '<meta name="ROBOTS" content="noindex">'
echo "</head><body><pre>"
date
echo "\nuname -a"
uname -a
echo "\ncpuinfo"
cat /proc/cpuinfo
echo "</pre></body></html>"
Also using this as an include file, not restricted to only shell scripts.
location ~ (\.cgi|\.py|\.sh|\.pl|\.lua)$ {
gzip off;
root /var/www/$server_name;
autoindex on;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include /etc/nginx/fastcgi_params;
fastcgi_param DOCUMENT_ROOT /var/www/$server_name;
fastcgi_param SCRIPT_FILENAME /var/www/$server_name$fastcgi_script_name;
}
I found it extremely helpful for what I am working on, I hope it help you out with your RaspberryPI project.

- 839
- 6
- 10
-
1See also https://www.nginx.com/resources/wiki/start/topics/examples/fcgiwrap/ and https://www.nginx.com/resources/wiki/start/topics/examples/fastcgiexample/ – Justin M. Keyes Nov 11 '15 at 23:13
-
I needed to set the right permissions on the shell script `sudo chmod 755 /var/www/www.example.com/cpu.sh` (found here https://www.howtoforge.com/serving-cgi-scripts-with-nginx-on-centos-6.0-p2) – adriaan Dec 23 '18 at 13:15
-
I found this article also quite helpful for this approach: https://sleeplessbeastie.eu/2017/09/18/how-to-execute-cgi-scripts-using-fcgiwrap/ – fei0x Feb 19 '21 at 15:35
If you prefer full control in Python:
- Create
/opt/httpbot.py
:
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import subprocess
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self._handle()
def do_POST(self):
self._handle()
def _handle(self):
try:
self.log_message("command: %s", self.path)
if self.path == '/foo':
subprocess.run(
"cd /opt/bar && GIT_SSH_COMMAND='ssh -i .ssh/id_rsa' git pull",
shell=True,
)
finally:
self.send_response(200)
self.send_header("content-type", "application/json")
self.end_headers()
self.wfile.write('{"ok": true}\r\n'.encode())
if __name__ == "__main__":
HTTPServer(("127.0.0.1", 4242), Handler).serve_forever()
- No concurrency/parallelism here, so
httpbot
runs one command at a time, no conflicts. - Run
apt install supervisor
- Create
/etc/supervisor/conf.d/httpbot.conf
:
[program:httpbot]
environment=PYTHONUNBUFFERED="TRUE"
directory=/opt
command=/opt/httpbot.py
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/httpbot.log
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=10
- Add to your nginx server:
location /foo {
proxy_pass http://127.0.0.1:4242/foo;
}
- Run:
chmod u+x /opt/httpbot.py
service supervisor status
# If stopped:
service supervisor start
supervisorctl status
# If httpbot is not running:
supervisorctl update
curl https://example.com/foo
# Should return {"ok": true}
tail /var/log/httpbot.log
# Should show `command: /foo` and the output of shell script

- 2,321
- 19
- 12
- Install OpenResty (OpenResty is just an enhanced version of Nginx by means of addon modules ) Refer https://openresty.org/en/getting-started.html for this
- Configure aws cli on the instance
- Write a shell script which download a file from specified S3 bucket
- Do the required changes in nginx.conf file
- Restart the nginx server
I have tested the http request using curl and file gets download in /tmp
directory of respective instance:
curl -I http://localhost:8080/
OutPut:
curl -I http://localhost:8080/
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Tue, 14 Aug 2018 07:34:49 GMT
Content-Type: text/plain
Connection: keep-alive
Content of nginx.conf file:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
default_type text/html;
content_by_lua '
ngx.say("<p>hello, world</p>")
';
}
location / {
content_by_lua_block{
os.execute("sh /tmp/s3.sh")
}
}
}
}

- 38,438
- 19
- 134
- 183

- 33
- 4
-
I haven't seen any shell script output and also, it says my file /tmp/s3.sh doesn't exist even though i created that file and it runs when i execute it directly. – Prashanth Apr 08 '19 at 03:43
-
My os.execute writes to stdout (i see it in nginx logs) but I got empty page in browser. – Dzenly Mar 03 '21 at 18:10
-
You can use nginx's perl module which is usually part of a repo and can be easily installed. Sample to call system curl command:
location /mint {
perl '
sub {
my $r = shift;
$r->send_http_header("text/html");
$r->print(`curl -X POST --data \'{"method":"evm_mine"}\' localhost:7545`);
return OK;
}
';
}

- 31
- 4
You can also use the nginx mirror module and poxy_pass it to a web script that runs whatever, in my case I just added this to my main site location {...
mirror /mirror;
mirror_request_body off;
and then a new location called mirror that I had run a php script that executed whatever...
location = /mirror {
internal;
proxy_pass http://localhost/run_script.php;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}

- 113
- 4