Reputation: 6542
I want to run a shell script every time my nginx server receives any HTTP request. Any simple ways to do this?
Upvotes: 96
Views: 133801
Reputation: 11789
Here is a hackish way to do it without any additional modules and without FastCGI:
nginxfeeder.socket
service, which will listen on a specified port, i.e. 8765, and invoke nginxfeeder.service:[Unit]
Description=Nginx callback status
[Socket]
ListenStream=127.0.0.1:8765
Accept=yes
[Install]
WantedBy=sockets.target
[email protected]
file invoked by this:[Service]
ExecStart=/opt/scripts/nginxhandler.sh
StandardError=journal
StandardInput=socket
StandardOutput=socket
User=wwwrun
Group=wwwrun
systemctl enable `pwd`/nginxfeeder.socket
systemctl enable `pwd`/[email protected]
systemctl start nginxfeeder.socket
Test it with telnet 127.0.0.1 8765
and you should see the output of your script.
Now your script is available at 127.0.0.1:8765 and you can use nginx proxy_pass
directive to have it invoked for a specific URL.
Upvotes: 4
Reputation: 123
You can also use the nginx mirror module and proxy_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 made 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;
}
https://nginx.org/en/docs/http/ngx_http_mirror_module.html
Upvotes: 0
Reputation: 2619
If you prefer full control in Python:
/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()
httpbot
runs one command at a time, no conflicts.apt install supervisor
/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
location /foo {
proxy_pass http://127.0.0.1:4242/foo;
}
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
Upvotes: 3
Reputation: 31
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;
}
';
}
Upvotes: 1
Reputation: 33
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")
}
}
}
}
Upvotes: 2
Reputation: 4526
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")
}
}
Upvotes: 85
Reputation: 889
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.
Upvotes: 62