mirror of
https://github.com/halverneus/static-file-server.git
synced 2024-11-24 09:05:30 +00:00
Added features for prepending a URL path prefix and for TLS support.
This commit is contained in:
parent
83ded2aab9
commit
dc99a50883
17
README.md
17
README.md
@ -5,12 +5,21 @@ Available on Docker Hub at https://hub.docker.com/r/halverneus/static-file-serve
|
||||
|
||||
Environment variables with defaults:
|
||||
```bash
|
||||
# Optional Hostname for binding. Leave black to accept any incoming HTTP request on the prescribed port.
|
||||
# Optional Hostname for binding. Leave black to accept any incoming HTTP request
|
||||
# on the prescribed port.
|
||||
HOST=
|
||||
# If assigned, must be a valid port number.
|
||||
PORT=8080
|
||||
# Folder with the content to serve.
|
||||
FOLDER=/web
|
||||
# URL path prefix. If 'my.file' is in the root of $FOLDER and $URL_PREFIX is
|
||||
# '/my/place' then file is retrieved with 'http://$HOST:$PORT/my/place/my.file'.
|
||||
URL_PREFIX=
|
||||
# Paths to the TLS certificate and key. If one is set then both must be set. If
|
||||
# both set then files are served using HTTPS. If neither are set then files are
|
||||
# served using HTTP.
|
||||
TLS_CERT=
|
||||
TLS_KEY=
|
||||
```
|
||||
|
||||
### Without Docker
|
||||
@ -30,4 +39,10 @@ Any of the variables can also be modified:
|
||||
docker run -d -v /home/me/dev/source:/content/html -v /home/me/dev/files:/content/more/files -e FOLDER=/content -p 8080:8080 halverneus/static-file-server:latest
|
||||
```
|
||||
|
||||
### Also try...
|
||||
```
|
||||
./serve help
|
||||
# OR
|
||||
docker run -it halverneus/static-file-server:latest help
|
||||
```
|
||||
This maybe a cheesy program, but it is convenient and less than 6MB in size.
|
||||
|
166
serve.go
166
serve.go
@ -1,21 +1,177 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "Version 1.1"
|
||||
|
||||
help = `
|
||||
NAME
|
||||
static-file-server
|
||||
|
||||
SYNOPSIS
|
||||
static-file-server
|
||||
static-file-server [ help | -help | --help ]
|
||||
static-file-server [ version | -version | --version ]
|
||||
|
||||
DESCRIPTION
|
||||
The Static File Server is intended to be a tiny, fast and simple solution
|
||||
for serving files over HTTP. The features included are limited to make to
|
||||
binding to a host name and port, selecting a folder to serve, choosing a
|
||||
URL path prefix and selecting TLS certificates. If you want really awesome
|
||||
reverse proxy features, I recommend Nginx.
|
||||
|
||||
DEPENDENCIES
|
||||
None... not even libc!
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
FOLDER
|
||||
The path to the folder containing the contents to be served over
|
||||
HTTP(s). If not supplied, defaults to '/web' (for Docker reasons).
|
||||
HOST
|
||||
The hostname used for binding. If not supplied, contents will be served
|
||||
to a client without regard for the hostname.
|
||||
PORT
|
||||
The port used for binding. If not supplied, defaults to port '8080'.
|
||||
TLS_CERT
|
||||
Path to the TLS certificate file to serve files using HTTPS. If supplied
|
||||
then TLS_KEY must also be supplied. If not supplied, contents will be
|
||||
served via HTTP.
|
||||
TLS_KEY
|
||||
Path to the TLS key file to serve files using HTTPS. If supplied then
|
||||
TLS_CERT must also be supplied. If not supplied, contents will be served
|
||||
via HTTPS
|
||||
URL_PREFIX
|
||||
The prefix to use in the URL path. If supplied, then the prefix must
|
||||
start with a forward-slash and NOT end with a forward-slash. If not
|
||||
supplied then no prefix is used.
|
||||
|
||||
USAGE
|
||||
FILE LAYOUT
|
||||
/var/www/sub/my.file
|
||||
|
||||
COMMAND
|
||||
export FOLDER=/var/www/sub
|
||||
static-file-server
|
||||
Retrieve with: wget http://localhost:8080/my.file
|
||||
wget http://my.machine:8080/my.file
|
||||
|
||||
export FOLDER=/var/www
|
||||
export HOST=my.machine
|
||||
export PORT=80
|
||||
static-file-server
|
||||
Retrieve with: wget http://my.machine/sub/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export HOST=my.machine
|
||||
export PORT=80
|
||||
export URL_PREFIX=/my/stuff
|
||||
static-file-server
|
||||
Retrieve with: wget http://my.machine/my/stuff/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export TLS_CERT=/etc/server/my.machine.crt
|
||||
export TLS_KEY=/etc/server/my.machine.key
|
||||
static-file-server
|
||||
Retrieve with: wget https://my.machine:8080/my.file
|
||||
|
||||
export FOLDER=/var/www/sub
|
||||
export PORT=443
|
||||
export TLS_CERT=/etc/server/my.machine.crt
|
||||
export TLS_KEY=/etc/server/my.machine.key
|
||||
static-file-server
|
||||
Retrieve with: wget https://my.machine/my.file
|
||||
`
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Evaluate and execute subcommand if supplied.
|
||||
if 1 < len(os.Args) {
|
||||
arg := os.Args[1]
|
||||
switch {
|
||||
case strings.Contains(arg, "help"):
|
||||
fmt.Println(help)
|
||||
case strings.Contains(arg, "version"):
|
||||
fmt.Println(version)
|
||||
default:
|
||||
name := os.Args[0]
|
||||
log.Fatalf("Unknown argument: %s. Try '%s help'.", arg, name)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Collect environment variables.
|
||||
folder := env("FOLDER", "/web") + "/"
|
||||
host := env("HOST", "")
|
||||
port := env("PORT", "8080")
|
||||
folder := env("FOLDER", "/web") + "/"
|
||||
tlsCert := env("TLS_CERT", "")
|
||||
tlsKey := env("TLS_KEY", "")
|
||||
urlPrefix := env("URL_PREFIX", "")
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, folder+r.URL.Path)
|
||||
})
|
||||
http.ListenAndServe(host+":"+port, nil)
|
||||
// If HTTPS is to be used, verify both TLS_* environment variables are set.
|
||||
if 0 < len(tlsCert) || 0 < len(tlsKey) {
|
||||
if 0 == len(tlsCert) || 0 == len(tlsKey) {
|
||||
log.Fatalln(
|
||||
"If value for environment variable 'TLS_CERT' or 'TLS_KEY' is set " +
|
||||
"then value for environment variable 'TLS_KEY' or 'TLS_CERT' must " +
|
||||
"also be set.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// If the URL path prefix is to be used, verify it is properly formatted.
|
||||
if 0 < len(urlPrefix) &&
|
||||
(!strings.HasPrefix(urlPrefix, "/") || strings.HasSuffix(urlPrefix, "/")) {
|
||||
log.Fatalln(
|
||||
"Value for environment variable 'URL_PREFIX' must start " +
|
||||
"with '/' and not end with '/'. Example: '/my/prefix'",
|
||||
)
|
||||
}
|
||||
|
||||
// Choose and set the appropriate, optimized static file serving function.
|
||||
var handler http.HandlerFunc
|
||||
if 0 == len(urlPrefix) {
|
||||
handler = basicHandler(folder)
|
||||
} else {
|
||||
handler = prefixHandler(folder, urlPrefix)
|
||||
}
|
||||
http.HandleFunc("/", handler)
|
||||
|
||||
// Serve files over HTTP or HTTPS based on paths to TLS files being provided.
|
||||
if 0 == len(tlsCert) {
|
||||
log.Fatalln(http.ListenAndServe(host+":"+port, nil))
|
||||
} else {
|
||||
log.Fatalln(http.ListenAndServeTLS(host+":"+port, tlsCert, tlsKey, nil))
|
||||
}
|
||||
}
|
||||
|
||||
// basicHandler serves files from the folder passed.
|
||||
func basicHandler(folder string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, folder+r.URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
// prefixHandler removes the URL path prefix before serving files from the
|
||||
// folder passed.
|
||||
func prefixHandler(folder, urlPrefix string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasPrefix(r.URL.Path, urlPrefix) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, r, folder+strings.TrimPrefix(r.URL.Path, urlPrefix))
|
||||
}
|
||||
}
|
||||
|
||||
// env returns the value for an environment variable or, if not set, a fallback
|
||||
// value.
|
||||
func env(key, fallback string) string {
|
||||
if value := os.Getenv(key); 0 < len(value) {
|
||||
return value
|
||||
|
Loading…
Reference in New Issue
Block a user