ShellinABox - ssh via www

Run ShellinABox, emulating a terminal in the browser. See how to configure Nginx as a reverse proxy, add SSL (HTTPS), and password protection (htpasswd)!

ssh via www

Sometimes there's a need to use our shell in places where the security policy is very restrictive and access is only possible to the most popular services. This is where applications that emulate a terminal in the browser come to our aid. As far as I know, there are three such programs on the market: AjaxTerm, AnyTerm, and ShellinABox. The first two require the user to install additional components, i.e. an Apache module and, in the case of AjaxTerm, the Python interpreter; also, the emulation of full-screen applications isn't perfect. The third program, ShellinABox, seems to be the best solution. Arguments in its favor:

  • it's a self-sufficient application (requires the OpenSSL package), it doesn't even require a web server.
  • thanks to full support for the VT100 terminal standard, it handles full-screen applications perfectly (Midnight Commander, htop, top, ekg)
  • SSL support
  • simple configuration
  • ...and finally the most important thing: it's really fast
  • support for Polish characters (UTF-8 encoding)
On the project's official website there's a demo of the interface.

Installing ShellinABox is simple. On the official ShellinABox website we'll find deb packages as well as source for compiling it ourselves. The OpenSSL library is required to run it. The file ShellinABoxd is used to run our terminal; the Debian/Ubuntu package installs a script in the /etc/init.d/ShellinABoxd directory. After starting, ShellinABox listens on all interfaces on port 4200, which wasn't necessarily what I wanted. We can force it to only work on localhost by adding the --localhost-only option at startup, or on Debian by adding ShellinABox_ARGS=--localhost-only to the /etc/default/ShellinABox file. Due to its young age, it suffers from childhood diseases. The biggest inconvenience is an issue with the SSL certificate leading to the program hanging. If we want to connect over https, then in theory ShellinABox should generate a certificate itself before its first run (with the help of OpenSSL), but it doesn't. We have to generate it ourselves and copy it to the program's directory, which on Debian is the directory /var/lib/ShellinABox. I haven't noticed this problem with the version from the official Debian repositories.
I decided against encryption in ShellinABox in favor of SSL on the web server, adding another layer of security in the form of password-based access authorization. In my solution I adopted the following assumptions: ShellinABox runs without encryption, only on the local host; the rest of the functionality, such as SSL, password access, and exposing it externally (reverse proxy), is handled by nginx. Another advantage of this solution is convenience - we don't have to type http://host:port_number into the browser, we can just use http://host .

  • Configuring ShellinABox

  • To restrict listening to the local interface on port 4200 and disable encryption, we edit the file /etc/default/ShellinABox
  • ShellinABox_PORT=4200 #set the port
    ShellinABox_ARGS=--localhost-only #restrict listening
    ShellinABox_ARGS=--disable-ssl #disable encryption

    After making changes, restart the program: /etc/init.d/ShellinABox
  • Configuring a reverse proxy using Nginx as an example

  • The example is based on configuring a virtual host to which we'll connect to reach our emulator. Remember to reconfigure your DNS.
  • Assuming that our domain is: dom.pl and the subdomain for ShellinABox is shl, we need to edit the dom.pl zone file, adding an entry (DNS server: BIND), and update the Serial:
  • shl IN A our.ip
    after the changes: rndc reload
  • We go to the /etc/nginx/sites-available/ directory and create the file shl:
  • file shl
    server {
            listen       80;											# we listen on the standard port 80
            server_name  shl.dom.pl;										# nginx itself will redirect us to https
             if ($host = 'shl.dom.pl' ) {										
                     rewrite  ^/(.*)$  https://shl.ulos.pl/$1  permanent;		
               }
    
            access_log /var/log/nginx/shl.access_log;
            error_log /var/log/nginx/shl.error_log;
    
    }
    server{														# ssl configuration
        listen 443;														
        ssl on;															
        server_name shl.ulos.pl;											
    
        ssl_certificate /etc/nginx/ssl/ssl.crt;											# we need to generate a certificate and key
        ssl_certificate_key /etc/nginx/ssl/ssl.key;							
    
        access_log /var/log/nginx/shl_ssl.access_log;
        error_log /var/log/nginx/shl_ssl.error_log;
    
    
            # Main location
            location / {													
                proxy_pass         http://127.0.0.1:4200/;										# we provide the ip:port on which ShellinABox is running
                proxy_redirect     default;										
    
                proxy_set_header   Host             $host;
                proxy_set_header   X-Real-IP        $remote_addr;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    
                client_max_body_size       10m;
                client_body_buffer_size    128k;
    
                proxy_connect_timeout      90;
                proxy_send_timeout         90;
                proxy_read_timeout         90;
    
                proxy_buffer_size          4k;
                proxy_buffers              4 32k;
                proxy_busy_buffers_size    64k;
                proxy_temp_file_write_size 64k;
    
                auth_basic "Restricted";												# additional security - authorization via password
                auth_basic_user_file /etc/nginx/.htpasswd;									
    
    
            }
    
    
    }
    
  • Let's comment out the last two lines (auth_basic...) in order to test this solution without the additional overhead of password authorization
  • we create a symbolic link: ln -s /etc/nginx/sites-available/shl /etc/nginx/sites-enabled/shl and restart Nginx: /etc/init.d/nginx restart
  • Now we can check whether everything is fine - type into the browser: http://shl.dom.pl, we should be redirected to https://shl.dom.pl; in case we don't have signed certificates, the browser will try to warn us, but we don't pay attention to it
  • If everything is fine, we can move on to the last stage, which is authorizing access to the site by providing a password. To generate the password we'll use the htpasswd script borrowed from Apache. It's bundled with Apache; we can also download just the script (libapache-htpasswd-perl) or use online generators.
  • we generate the file: htpasswd -c path_to_file username

At this point we have a solution that's much better in terms of functionality and cheaper than commercial offerings, which are mostly based on AjaxTerm