Compare commits
No commits in common. "master" and "dev/gh-actions" have entirely different histories.
master
...
dev/gh-act
5 changed files with 15 additions and 116 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
||||||
vendor/
|
vendor/
|
||||||
goStatic*
|
goStatic
|
||||||
|
|
18
README.md
18
README.md
|
@ -1,24 +1,6 @@
|
||||||
# goStatic [](https://hub.docker.com/r/pierrezemb/gostatic/) [](https://hub.docker.com/r/pierrezemb/gostatic/) [](https://travis-ci.org/PierreZ/goStatic) [](https://godoc.org/github.com/PierreZ/goStatic)
|
# goStatic [](https://hub.docker.com/r/pierrezemb/gostatic/) [](https://hub.docker.com/r/pierrezemb/gostatic/) [](https://travis-ci.org/PierreZ/goStatic) [](https://godoc.org/github.com/PierreZ/goStatic)
|
||||||
A really small, multi-arch, static web server for Docker
|
A really small, multi-arch, static web server for Docker
|
||||||
|
|
||||||
# La mia applicazione
|
|
||||||
|
|
||||||
with docker
|
|
||||||
|
|
||||||
sudo docker run -d -p 8120:8043 -v /home/nvme/dockerdata/myweb:/srv/http --name myweb pierrezemb/gostatic
|
|
||||||
|
|
||||||
with docker compose or portainer
|
|
||||||
|
|
||||||
services:
|
|
||||||
gostatic:
|
|
||||||
ports:
|
|
||||||
- 8120:8043
|
|
||||||
volumes:
|
|
||||||
- /home/nvme/dockerdata/myweb:/srv/http
|
|
||||||
container_name: myweb
|
|
||||||
image: pierrezemb/gostatic
|
|
||||||
command: -set-basic-auth fabio:master66 #set auth login
|
|
||||||
|
|
||||||
## The goal
|
## The goal
|
||||||
My goal is to create to smallest docker container for my web static files. The advantage of Go is that you can generate a fully static binary, so that you don't need anything else.
|
My goal is to create to smallest docker container for my web static files. The advantage of Go is that you can generate a fully static binary, so that you don't need anything else.
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,5 +1,3 @@
|
||||||
module github.com/PierreZ/goStatic
|
module github.com/PierreZ/goStatic
|
||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require github.com/rs/zerolog v1.26.1
|
|
||||||
|
|
32
go.sum
32
go.sum
|
@ -1,32 +0,0 @@
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
|
||||||
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
|
||||||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
77
main.go
77
main.go
|
@ -9,14 +9,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -31,8 +28,7 @@ var (
|
||||||
setBasicAuth = flag.String("set-basic-auth", "", "Define the basic auth. Form must be user:password")
|
setBasicAuth = flag.String("set-basic-auth", "", "Define the basic auth. Form must be user:password")
|
||||||
defaultUsernameBasicAuth = flag.String("default-user-basic-auth", "gopher", "Define the user")
|
defaultUsernameBasicAuth = flag.String("default-user-basic-auth", "gopher", "Define the user")
|
||||||
sizeRandom = flag.Int("password-length", 16, "Size of the randomized password")
|
sizeRandom = flag.Int("password-length", 16, "Size of the randomized password")
|
||||||
logLevel = flag.String("log-level", "info", "default: info - What level of logging to run, debug logs all requests (error, warn, info, debug)")
|
logRequest = flag.Bool("enable-logging", false, "Enable log request")
|
||||||
logRequest = flag.Bool("enable-logging", false, "Enable log request. NOTE: Deprecated, set log-level to debug to log all requests")
|
|
||||||
httpsPromote = flag.Bool("https-promote", false, "All HTTP requests should be redirected to HTTPS")
|
httpsPromote = flag.Bool("https-promote", false, "All HTTP requests should be redirected to HTTPS")
|
||||||
headerConfigPath = flag.String("header-config-path", "/config/headerConfig.json", "Path to the config file for custom response headers")
|
headerConfigPath = flag.String("header-config-path", "/config/headerConfig.json", "Path to the config file for custom response headers")
|
||||||
|
|
||||||
|
@ -40,21 +36,6 @@ var (
|
||||||
password string
|
password string
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupLogger(logLevel string) {
|
|
||||||
switch logLevel {
|
|
||||||
case "error":
|
|
||||||
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
|
||||||
case "warn":
|
|
||||||
zerolog.SetGlobalLevel(zerolog.WarnLevel)
|
|
||||||
case "info":
|
|
||||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
||||||
case "debug":
|
|
||||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
|
||||||
default:
|
|
||||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseHeaderFlag(headerFlag string) (string, string) {
|
func parseHeaderFlag(headerFlag string) (string, string) {
|
||||||
if len(headerFlag) == 0 {
|
if len(headerFlag) == 0 {
|
||||||
return "", ""
|
return "", ""
|
||||||
|
@ -91,10 +72,16 @@ func handleReq(h http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if *httpsPromote && r.Header.Get("X-Forwarded-Proto") == "http" {
|
if *httpsPromote && r.Header.Get("X-Forwarded-Proto") == "http" {
|
||||||
http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
|
http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
|
||||||
log.Debug().Int("http_code", 301).Str("Method", r.Method).Str("Path", r.URL.Path).Msg("Request Redirected")
|
if *logRequest {
|
||||||
|
log.Println(301, r.Method, r.URL.Path)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug().Str("Method", r.Method).Str("Path", r.URL.Path).Msg("Request Handled")
|
|
||||||
|
if *logRequest {
|
||||||
|
log.Println(r.Method, r.URL.Path)
|
||||||
|
}
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -103,46 +90,16 @@ func main() {
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Setting up logging output before setting up level to print out deprecation warnings
|
|
||||||
// UNIX Time is faster and smaller than most timestamps
|
|
||||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
|
||||||
|
|
||||||
// Set a pretty console output
|
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
|
||||||
|
|
||||||
if *logRequest {
|
|
||||||
log.Warn().Msg("enable-logging is deprecated in favor of log-level")
|
|
||||||
}
|
|
||||||
|
|
||||||
//if log-level not default and enable-logging set to true, use log-level
|
|
||||||
if *logLevel != "info" && *logRequest {
|
|
||||||
log.Warn().Msg("log-level not 'info' and enable-logging set, using log-level")
|
|
||||||
*logRequest = false
|
|
||||||
}
|
|
||||||
|
|
||||||
//if log-level is info and we have enable-logging, set log-level to debug
|
|
||||||
if *logLevel == "info" && *logRequest {
|
|
||||||
log.Warn().Msg("since enable-logging is set, setting log-level to debug")
|
|
||||||
*logLevel = "debug"
|
|
||||||
}
|
|
||||||
|
|
||||||
//setting up the logger
|
|
||||||
setupLogger(*logLevel)
|
|
||||||
log.Debug().Str("Logging Level", zerolog.GlobalLevel().String()).Msg("Logger setup...")
|
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if len(*setBasicAuth) != 0 && !*basicAuth {
|
if len(*setBasicAuth) != 0 && !*basicAuth {
|
||||||
log.Debug().Msg("Basic Auth Set")
|
|
||||||
*basicAuth = true
|
*basicAuth = true
|
||||||
}
|
}
|
||||||
|
|
||||||
port := ":" + strconv.FormatInt(int64(*portPtr), 10)
|
port := ":" + strconv.FormatInt(int64(*portPtr), 10)
|
||||||
|
|
||||||
var fileSystem http.FileSystem = http.Dir(*basePath)
|
var fileSystem http.FileSystem = http.Dir(*basePath)
|
||||||
log.Debug().Str("path", *basePath).Msg("File serve path set")
|
|
||||||
|
|
||||||
if *fallbackPath != "" {
|
if *fallbackPath != "" {
|
||||||
log.Debug().Str("FallbackPath", *fallbackPath).Msg("Fallback path set")
|
|
||||||
fileSystem = fallback{
|
fileSystem = fallback{
|
||||||
defaultPath: *fallbackPath,
|
defaultPath: *fallbackPath,
|
||||||
fs: fileSystem,
|
fs: fileSystem,
|
||||||
|
@ -158,7 +115,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *basicAuth {
|
if *basicAuth {
|
||||||
log.Debug().Msg("Enabling Basic Auth")
|
log.Println("Enabling Basic Auth")
|
||||||
if len(*setBasicAuth) != 0 {
|
if len(*setBasicAuth) != 0 {
|
||||||
parseAuth(*setBasicAuth)
|
parseAuth(*setBasicAuth)
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,7 +135,6 @@ func main() {
|
||||||
if len(header) > 0 && len(headerValue) > 0 {
|
if len(header) > 0 && len(headerValue) > 0 {
|
||||||
fileServer := handler
|
fileServer := handler
|
||||||
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Debug().Str("URL", r.URL.Path).Str("header", header).Str("headerValue", headerValue).Msg("Extra Headers Handled")
|
|
||||||
w.Header().Set(header, headerValue)
|
w.Header().Set(header, headerValue)
|
||||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
|
||||||
fileServer.ServeHTTP(w, r)
|
fileServer.ServeHTTP(w, r)
|
||||||
|
@ -190,27 +146,22 @@ func main() {
|
||||||
gz.Reset(w)
|
gz.Reset(w)
|
||||||
defer gz.Close()
|
defer gz.Close()
|
||||||
fileServer.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r)
|
fileServer.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
log.Warn().Msg("appendHeader misconfigured; ignoring.")
|
log.Println("appendHeader misconfigured; ignoring.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *healthCheck {
|
if *healthCheck {
|
||||||
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Debug().Msg("Returning Service Health")
|
|
||||||
fmt.Fprintf(w, "Ok")
|
fmt.Fprintf(w, "Ok")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Handle(pathPrefix, handler)
|
http.Handle(pathPrefix, handler)
|
||||||
|
|
||||||
log.Info().Msgf("Listening at http://0.0.0.0%v %v...", port, pathPrefix)
|
log.Printf("Listening at 0.0.0.0%v %v...", port, pathPrefix)
|
||||||
if err := http.ListenAndServe(port, nil); err != nil && err != http.ErrServerClosed {
|
log.Fatalln(http.ListenAndServe(port, nil))
|
||||||
log.Fatal().Err(err).Msg("Server startup failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue