Browse Source

Intial commit

Abhinav Sarkar 1 year ago
commit
28a534d74d
9 changed files with 198 additions and 0 deletions
  1. 3
    0
      .gitignore
  2. 7
    0
      Dockerfile
  3. 30
    0
      LICENSE
  4. 45
    0
      README.md
  5. 2
    0
      Setup.hs
  6. 34
    0
      hastatic.cabal
  7. 30
    0
      package.yaml
  8. 43
    0
      src/Main.hs
  9. 4
    0
      stack.yaml

+ 3
- 0
.gitignore View File

@@ -0,0 +1,3 @@
1
+.stack-work/
2
+abhinavsarkar-net-server.cabal
3
+*~

+ 7
- 0
Dockerfile View File

@@ -0,0 +1,7 @@
1
+FROM haskell:8.4.3 as builder
2
+WORKDIR /opt/hastatic
3
+ADD . .
4
+RUN stack install && strip /root/.local/bin/hastatic
5
+
6
+FROM fpco/haskell-scratch:integer-gmp
7
+COPY --from=builder /root/.local/bin/hastatic /usr/bin/hastatic

+ 30
- 0
LICENSE View File

@@ -0,0 +1,30 @@
1
+Copyright Abhinav Sarkar (c) 2018
2
+
3
+All rights reserved.
4
+
5
+Redistribution and use in source and binary forms, with or without
6
+modification, are permitted provided that the following conditions are met:
7
+
8
+    * Redistributions of source code must retain the above copyright
9
+      notice, this list of conditions and the following disclaimer.
10
+
11
+    * Redistributions in binary form must reproduce the above
12
+      copyright notice, this list of conditions and the following
13
+      disclaimer in the documentation and/or other materials provided
14
+      with the distribution.
15
+
16
+    * Neither the name of Abhinav Sarkar nor the names of other
17
+      contributors may be used to endorse or promote products derived
18
+      from this software without specific prior written permission.
19
+
20
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 45
- 0
README.md View File

@@ -0,0 +1,45 @@
1
+# hastatic
2
+
3
+_hastatic_ is a tiny static web server for Docker.
4
+
5
+## Features
6
+
7
+- A tiny web server, just 3MB in size.
8
+- Statically compiled binary with no dependencies.
9
+- Built for Docker.
10
+- Supports custom 404 file.
11
+- Supports custom index files for URLs ending with "/".
12
+- Adds caching headers automatically.
13
+- Does not support HTTPS. It is expected that you run it behind a reverse-proxy server with HTTPS support, like nginx.
14
+
15
+## Usage
16
+
17
+Create a Dockerfile for your website, deriving from `abhin4v/hastatic`:
18
+
19
+```dockerfile
20
+FROM abhin4v/hastatic:latest
21
+
22
+COPY mywebsite /opt/mywebsite
23
+WORKDIR /opt/mywebsite
24
+CMD ["/usr/bin/hastatic"]
25
+```
26
+
27
+Build and run:
28
+
29
+```
30
+$ docker build -t mywebsite .
31
+$ docker run -p 8080:3000 mywebsite # run with default configs
32
+$ docker run -e PORT=2000 -e NF_FILE=404.html -e IDX_FILE=index.html -p 8080:2000 mywebsite
33
+```
34
+
35
+## Configuration
36
+
37
+The Docker image supports these environment variable for configuration:
38
+
39
+- PORT: the port to run the web server on, default: 3000
40
+- NF_FILE: name of the custom 404 file, default: `404.html`
41
+- IDX_FILE: name of the custom index files, default: `index.html`
42
+
43
+## Internals
44
+
45
+_hastatic_ is written in Haskell, just 30 lines of it. It uses the excellent [Warp](https://hackage.haskell.org/package/warp) server underneath.

+ 2
- 0
Setup.hs View File

@@ -0,0 +1,2 @@
1
+import Distribution.Simple
2
+main = defaultMain

+ 34
- 0
hastatic.cabal View File

@@ -0,0 +1,34 @@
1
+-- This file has been generated from package.yaml by hpack version 0.28.2.
2
+--
3
+-- see: https://github.com/sol/hpack
4
+--
5
+-- hash: e49204f2f26a2ed8552e95f4f543b1cb4148cc509790f5d550ab98b70a722323
6
+
7
+name:           hastatic
8
+version:        0.9.0
9
+description:    Please see the README on GitHub at <https://github.com/abhin4v/hastatic#readme>
10
+author:         Abhinav Sarkar
11
+maintainer:     abhinav@abhinavsarkar.net
12
+copyright:      2018 Abhinav Sarkar
13
+license:        BSD3
14
+license-file:   LICENSE
15
+build-type:     Simple
16
+cabal-version:  >= 1.10
17
+extra-source-files:
18
+    README.md
19
+
20
+executable hastatic
21
+  main-is: Main.hs
22
+  other-modules:
23
+      Paths_hastatic
24
+  hs-source-dirs:
25
+      src
26
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N -O2
27
+  build-depends:
28
+      base >=4.7 && <5
29
+    , http-types
30
+    , text
31
+    , wai
32
+    , wai-middleware-static
33
+    , warp
34
+  default-language: Haskell2010

+ 30
- 0
package.yaml View File

@@ -0,0 +1,30 @@
1
+name:                hastatic
2
+version:             0.9.0
3
+license:             BSD3
4
+author:              "Abhinav Sarkar"
5
+maintainer:          "abhinav@abhinavsarkar.net"
6
+copyright:           "2018 Abhinav Sarkar"
7
+
8
+extra-source-files:
9
+- README.md
10
+
11
+description:         Please see the README on GitHub at <https://github.com/abhin4v/hastatic#readme>
12
+
13
+dependencies:
14
+- base >= 4.7 && < 5
15
+
16
+executables:
17
+  hastatic:
18
+    main:                Main.hs
19
+    source-dirs:         src
20
+    ghc-options:
21
+    - -threaded
22
+    - -rtsopts
23
+    - -with-rtsopts=-N
24
+    - -O2
25
+    dependencies:
26
+    - wai
27
+    - warp
28
+    - http-types
29
+    - wai-middleware-static
30
+    - text

+ 43
- 0
src/Main.hs View File

@@ -0,0 +1,43 @@
1
+{-# LANGUAGE OverloadedStrings #-}
2
+module Main where
3
+
4
+import Data.Maybe (fromMaybe)
5
+import qualified Data.List as List
6
+import qualified Data.Text as T
7
+import Network.Wai
8
+import Network.Wai.Middleware.Static
9
+import Network.HTTP.Types (status404)
10
+import Network.Wai.Handler.Warp (run)
11
+import System.Environment (lookupEnv)
12
+import Text.Read (readMaybe)
13
+
14
+indexHTML :: T.Text -> Middleware
15
+indexHTML indexFile app req respond =
16
+  let path = pathInfo req
17
+  in flip app respond $ req { pathInfo = fixPath path }
18
+  where
19
+    fixPath path = case path of
20
+      []     -> [indexFile]
21
+      [""]   -> [indexFile]
22
+      [x]    -> if "." `T.isInfixOf` x then [x] else [x, indexFile]
23
+      (x:xs) -> x : fixPath xs
24
+
25
+notFoundHandler notFoundFile _ respond = respond $
26
+  responseFile status404 [("Content-Type", "text/html")] notFoundFile Nothing
27
+
28
+main = do
29
+  mPort <- lookupEnv "PORT"
30
+  let port = fromMaybe 3000 (readMaybe =<< mPort)
31
+  mNotFoundFile <- lookupEnv "NF_FILE"
32
+  let notFoundFile = fromMaybe "404.html" mNotFoundFile
33
+  mIndexFile <- lookupEnv "IDX_FILE"
34
+  let indexFile = T.pack $ fromMaybe "index.html" mIndexFile
35
+
36
+  cache <- initCaching PublicStaticCaching
37
+  putStrLn $ "Starting server on port: " <> show port
38
+  run port
39
+    $ indexHTML indexFile
40
+    $ staticPolicy' cache (predicate noDot)
41
+    $ notFoundHandler notFoundFile
42
+  where
43
+    noDot = not . List.isPrefixOf "."

+ 4
- 0
stack.yaml View File

@@ -0,0 +1,4 @@
1
+resolver: lts-12.1
2
+
3
+packages:
4
+- .

Loading…
Cancel
Save