commit
28a534d74d
@ -0,0 +1,3 @@ |
||||
.stack-work/ |
||||
abhinavsarkar-net-server.cabal |
||||
*~ |
@ -0,0 +1,7 @@ |
||||
FROM haskell:8.4.3 as builder |
||||
WORKDIR /opt/hastatic |
||||
ADD . . |
||||
RUN stack install && strip /root/.local/bin/hastatic |
||||
|
||||
FROM fpco/haskell-scratch:integer-gmp |
||||
COPY --from=builder /root/.local/bin/hastatic /usr/bin/hastatic |
@ -0,0 +1,30 @@ |
||||
Copyright Abhinav Sarkar (c) 2018 |
||||
|
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above |
||||
copyright notice, this list of conditions and the following |
||||
disclaimer in the documentation and/or other materials provided |
||||
with the distribution. |
||||
|
||||
* Neither the name of Abhinav Sarkar nor the names of other |
||||
contributors may be used to endorse or promote products derived |
||||
from this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,45 @@ |
||||
# hastatic |
||||
|
||||
_hastatic_ is a tiny static web server for Docker. |
||||
|
||||
## Features |
||||
|
||||
- A tiny web server, just 3MB in size. |
||||
- Statically compiled binary with no dependencies. |
||||
- Built for Docker. |
||||
- Supports custom 404 file. |
||||
- Supports custom index files for URLs ending with "/". |
||||
- Adds caching headers automatically. |
||||
- Does not support HTTPS. It is expected that you run it behind a reverse-proxy server with HTTPS support, like nginx. |
||||
|
||||
## Usage |
||||
|
||||
Create a Dockerfile for your website, deriving from `abhin4v/hastatic`: |
||||
|
||||
```dockerfile |
||||
FROM abhin4v/hastatic:latest |
||||
|
||||
COPY mywebsite /opt/mywebsite |
||||
WORKDIR /opt/mywebsite |
||||
CMD ["/usr/bin/hastatic"] |
||||
``` |
||||
|
||||
Build and run: |
||||
|
||||
``` |
||||
$ docker build -t mywebsite . |
||||
$ docker run -p 8080:3000 mywebsite # run with default configs |
||||
$ docker run -e PORT=2000 -e NF_FILE=404.html -e IDX_FILE=index.html -p 8080:2000 mywebsite |
||||
``` |
||||
|
||||
## Configuration |
||||
|
||||
The Docker image supports these environment variable for configuration: |
||||
|
||||
- PORT: the port to run the web server on, default: 3000 |
||||
- NF_FILE: name of the custom 404 file, default: `404.html` |
||||
- IDX_FILE: name of the custom index files, default: `index.html` |
||||
|
||||
## Internals |
||||
|
||||
_hastatic_ is written in Haskell, just 30 lines of it. It uses the excellent [Warp](https://hackage.haskell.org/package/warp) server underneath. |
@ -0,0 +1,34 @@ |
||||
-- This file has been generated from package.yaml by hpack version 0.28.2. |
||||
-- |
||||
-- see: https://github.com/sol/hpack |
||||
-- |
||||
-- hash: e49204f2f26a2ed8552e95f4f543b1cb4148cc509790f5d550ab98b70a722323 |
||||
|
||||
name: hastatic |
||||
version: 0.9.0 |
||||
description: Please see the README on GitHub at <https://github.com/abhin4v/hastatic#readme> |
||||
author: Abhinav Sarkar |
||||
maintainer: abhinav@abhinavsarkar.net |
||||
copyright: 2018 Abhinav Sarkar |
||||
license: BSD3 |
||||
license-file: LICENSE |
||||
build-type: Simple |
||||
cabal-version: >= 1.10 |
||||
extra-source-files: |
||||
README.md |
||||
|
||||
executable hastatic |
||||
main-is: Main.hs |
||||
other-modules: |
||||
Paths_hastatic |
||||
hs-source-dirs: |
||||
src |
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O2 |
||||
build-depends: |
||||
base >=4.7 && <5 |
||||
, http-types |
||||
, text |
||||
, wai |
||||
, wai-middleware-static |
||||
, warp |
||||
default-language: Haskell2010 |
@ -0,0 +1,30 @@ |
||||
name: hastatic |
||||
version: 0.9.0 |
||||
license: BSD3 |
||||
author: "Abhinav Sarkar" |
||||
maintainer: "abhinav@abhinavsarkar.net" |
||||
copyright: "2018 Abhinav Sarkar" |
||||
|
||||
extra-source-files: |
||||
- README.md |
||||
|
||||
description: Please see the README on GitHub at <https://github.com/abhin4v/hastatic#readme> |
||||
|
||||
dependencies: |
||||
- base >= 4.7 && < 5 |
||||
|
||||
executables: |
||||
hastatic: |
||||
main: Main.hs |
||||
source-dirs: src |
||||
ghc-options: |
||||
- -threaded |
||||
- -rtsopts |
||||
- -with-rtsopts=-N |
||||
- -O2 |
||||
dependencies: |
||||
- wai |
||||
- warp |
||||
- http-types |
||||
- wai-middleware-static |
||||
- text |
@ -0,0 +1,43 @@ |
||||
{-# LANGUAGE OverloadedStrings #-} |
||||
module Main where |
||||
|
||||
import Data.Maybe (fromMaybe) |
||||
import qualified Data.List as List |
||||
import qualified Data.Text as T |
||||
import Network.Wai |
||||
import Network.Wai.Middleware.Static |
||||
import Network.HTTP.Types (status404) |
||||
import Network.Wai.Handler.Warp (run) |
||||
import System.Environment (lookupEnv) |
||||
import Text.Read (readMaybe) |
||||
|
||||
indexHTML :: T.Text -> Middleware |
||||
indexHTML indexFile app req respond = |
||||
let path = pathInfo req |
||||
in flip app respond $ req { pathInfo = fixPath path } |
||||
where |
||||
fixPath path = case path of |
||||
[] -> [indexFile] |
||||
[""] -> [indexFile] |
||||
[x] -> if "." `T.isInfixOf` x then [x] else [x, indexFile] |
||||
(x:xs) -> x : fixPath xs |
||||
|
||||
notFoundHandler notFoundFile _ respond = respond $ |
||||
responseFile status404 [("Content-Type", "text/html")] notFoundFile Nothing |
||||
|
||||
main = do |
||||
mPort <- lookupEnv "PORT" |
||||
let port = fromMaybe 3000 (readMaybe =<< mPort) |
||||
mNotFoundFile <- lookupEnv "NF_FILE" |
||||
let notFoundFile = fromMaybe "404.html" mNotFoundFile |
||||
mIndexFile <- lookupEnv "IDX_FILE" |
||||
let indexFile = T.pack $ fromMaybe "index.html" mIndexFile |
||||
|
||||
cache <- initCaching PublicStaticCaching |
||||
putStrLn $ "Starting server on port: " <> show port |
||||
run port |
||||
$ indexHTML indexFile |
||||
$ staticPolicy' cache (predicate noDot) |
||||
$ notFoundHandler notFoundFile |
||||
where |
||||
noDot = not . List.isPrefixOf "." |
@ -0,0 +1,4 @@ |
||||
resolver: lts-12.1 |
||||
|
||||
packages: |
||||
- . |
Loading…
Reference in new issue