Joel Kleier's Electric Froth

up

Neat tricks for having a local static file server

by Joel Kleier on 2018-03-03


Sometimes I just need to see a local directory served statically, and just using file:// URL’s don’t cut it.

The quickest and easiest, often, for me is to just use python:

$ python2 -m SimpleHTTPServer 8080

for python 2.7, and:

$ python3 -m http.server 8080

for python 3.x — I usually have one or the other installed, it’s in the standard library so there’s no fussing about packages, and it’s super simple to remember.

Another really convenient utility, especially so if you deal with node.js based development, is to use http-server:

$ npm install -g http-server
$ http-server

A bit more configurable through arguments than the python modules, it’s a pretty great utility. Downside: requires node.js + installing a package — two very common and easy things, but not always things I have setup locally. Node.js isn’t installed by default whereas python usually is for *nix systems.

The last utility I use is a mashup, and a fair bit more complex: Docker + NGINX!

It’s pretty useful if you want a service that uses tools you might use in a production environment, it puts a lot more tools at my disposal, and it can be pretty conveniently daemonized.

First, I create a bash script I keep on my path (I called mine shere):

#!/bin/bash

# defaults
SERVING_ON_PORT="8080"
DAEMON_OPT="-d"

# grab arguments
POSITIONAL=()
while [[ $# -gt 0 ]]
do
    key="$1"
    case $key in
    -p|--port)
        SERVING_ON_PORT="$2"
        shift # past arg
        shift # past val
    ;;
    -dd|--dontdaemonize)
        DAEMON_OPT=""
        shift
    ;;
    -h|--help)
        echo "$0 [-h|--help] [-dd|--dontdaemonize] [-p|--port <port>]"
        exit
    ;;
    *)
    POSITIONAL+=("$1")
    shift
    esac
done

# restore positional args, though none are expected at this point
set -- "${POSITIONAL[@]}"

# run docker
echo "docker nginx starting on 127.0.0.1:${SERVING_ON_PORT}..."
docker run $DAEMON_OPT --rm --name static${SERVING_ON_PORT} -p ${SERVING_ON_PORT}:80 -v $HOME/etc/nginx.conf:/etc/nginx/nginx.conf:ro -v ${PWD}:/usr/share/nginx/html:ro nginx

I also keep a nginx config file for the container at $HOME/etc/nginx.conf, which looks like:

user  nginx;
worker_processes  1;

#error_log  /var/log/nginx/error.log warn;
error_log /dev/stdout warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  /var/log/nginx/access.log  main;
    access_log /dev/stdout;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    autoindex on;

    include /etc/nginx/conf.d/*.conf;
}

The differences from default, in this case, are that I enable autoindex, and I pipe the error log and access log to stder/stdout.

And that’s it! The Docker+NGINX solution is a bit more complex, and takes some time to set up, but it can certainly be convenient!