ssh
into the machine but sometimes there needs to be an easier way.Most of my RPi units are headless and will run 24/7 - having to log in to the host for basic monitoring can be a real pain, requiring another host (typically a PC or laptop), just to check basic/simple status. Whilst requesting a simple shutdown or restart can be acheived with a phsical push button (normal-open momentary) switch paired with a python script it does mean that you actually need to obtain the push button.
I wanted another solution.
My basic requirements:
- perform pre-defined suite of actions without another PC/via
ssh
- shutdown or restart machine
- force restart of troublesome/intermittent services (like
bluetooth
wichi will consume CPU if a bluetooth keyboard suddenly disappears) - start/stop playing pre-defined web radio station
- provide consolidated view of pre-defined system status (filesystem free space, current established connections, summary of top processes)
- password protect access to the same maintanence system from outside of the home network/other side of firewall
Since all of my RPi units will be connected to my home network or at least reachable via some known IP or name the solution to these requirements can be provided through a simple webpage hosted on each RPi (using
lighttpd
as the webserver) and backed by a set of cgi scripts.Basic lighttpd
setup
A webserver is easily the most appropriate solution providing an interface to smart phones/tablets to interact with the host as well as bigger machines. The interface to the backend scripts can also be very simple (hitting a URL mapping to backend cgi script or it can be a more complicated webpage built using jquery/ajax/anjular/bootstrap technologies etc. Whilst this could be taken further with REST apis etc it is careful not to overengineer the solution and create a resource hogging server on the RPi side.The basic configuration to enable http to https redirection as well as filtering based on remote (client side) IP.
# /etc/lighttpd/lighttpd.conf server.modules = ( "mod_auth", "mod_access", "mod_alias", "mod_compress", "mod_redirect", "mod_rewrite", "mod_proxy", ) var.server_root = "/var/www" server.document-root = "/var/www/html" server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) server.errorlog = "/var/log/lighttpd/error.log" server.pid-file = "/var/run/lighttpd.pid" server.username = "www-data" server.groupname = "www-data" server.port = 80 auth.backend = "htdigest" auth.backend.htdigest.userfile = "/etc/lighttpd/htdigest.user" index-file.names = ( "index.php", "index.html", "index.lighttpd.html" ) url.access-deny = ( "~", ".inc" ) static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" ) compress.cache-dir = "/var/cache/lighttpd/compress/" compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" ) # default listening port for IPv6 falls back to the IPv4 port include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port include_shell "/usr/share/lighttpd/create-mime.assign.pl" include_shell "/usr/share/lighttpd/include-conf-enabled.pl" ## enable https and generate cert ## openssl req -new -x509 \ ## -keyout /etc/lighttpd/certs/lighttpd.pem \ ## -out /etc/lighttpd/certs/lighttpd.pem \ ## -days 3650 \ ## -nodes $SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/certs/lighttpd.pem" } ## force all http -> https $HTTP["scheme"] == "http" { # capture vhost name with regex conditiona -> %0 in redirect pattern # must be the most inner block to the redirect rule $HTTP["host"] =~ ".*" { url.redirect = (".*" => "https://%0$0") } } ## internal network is 192.168.0.x - promopt all external traffic for passwd ## should already have been routed to https $HTTP["remoteip"] != "192.168.0.0/16" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/certs/lighttpd.pem" server.errorlog = "/var/log/lighttpd/error-extnl.log" # accesslog.filename = "/var/log/lighttpd/access-extnl.log" auth.require = ( "/" => ( "method" => "digest", "realm" => "realm", "require" => "valid-user" ) ) }
lighttpd
on Raspbian auto pulls in files in the conf-enabled
folder:Note that to enable correct handling of bash cgi scripts we must map# /etc/lighttpd/conf-enabled/10-cgi.conf server.modules += ( "mod_cgi" ) cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".rb" => "/usr/bin/ruby", ".erb" => "/usr/bin/eruby", ".py" => "/usr/bin/python", ".sh" => "/bin/bash" ) alias.url += ( "/cgi-bin" => server_root + "/cgi-bin" ) $HTTP["url"] =~ "^/cgi-bin" { cgi.assign = ( "" => "" ) }
.sh
files to be started using /bin/bash
explicitly via the cgi.assign
- it appears that the #!/bin/bash
at the top of your cgi scripts are ignored and /bin/sh
is not a symlink to bash
.Additionally, with the
alias.url
directive, we can call cgi files with /cgi-bin/foo.sh
for the files to be outside of the document_root
Choice of Frontend
The webpage frontend is built using bootstrap/js so it will should be suitable for small screen devices as well as larger counterparts and data requests/responses will be handled via ajax to remove the need for full webpage reloads to have informational sections on the webpage update.The bulk of the webpage is to provide information sent back from the server to indicate the server status.
Letting cgi-bin
work
The webserver will run as the www-data
user so we will need to grant access to the relevant system commands via sudo:Again this means that anyone with access to your network will be able to run the cgi scripts although we've added a simple passwd requirement for anyone coming from outside of the network. However, if anyone is on our network it means they're probably close enough to come and rip the power out of the RPi anyway so it's not a great concern.# /etc/sudoers www-data ALL=(ALL) NOPASSWD: /sbin/shutdown, /usr/bin/mocp-bbcradio.sh, /usr/bin/mocp, /bin/systemctl
The files for webpage are available on github
No comments:
Post a Comment