feat: moved services from source to here, still untested: vsftpd,

mongodb, mysql, nginx
This commit is contained in:
Mahdi Dibaiee
2017-03-18 18:06:18 +03:30
parent a5cc8582fc
commit 5550b17522
22 changed files with 990 additions and 8 deletions

View File

@ -0,0 +1,24 @@
name: serverman-service-nginx
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/githubuser/nginx#readme
license: GPL-3
license-file: LICENSE
author: Author name here
maintainer: example@example.com
copyright: 2017 Author name here
category: Web
build-type: Simple
cabal-version: >=1.10
extra-source-files: README.md
executable nginx
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5
, data-default-class
, monad-control
, mtl
, free

BIN
services/nginx/src/Main Executable file

Binary file not shown.

BIN
services/nginx/src/Main.hi Normal file

Binary file not shown.

126
services/nginx/src/Main.hs Normal file
View File

@ -0,0 +1,126 @@
{-# LANGUAGE NamedFieldPuns #-}
module Main (call, main) where
import System.Serverman.Types
import System.Serverman.Utils
import Types
import System.Directory
import System.IO
import System.IO.Error
import System.FilePath
import System.Process
import Control.Concurrent.Async
import Control.Monad
import Control.Monad.State
import Control.Monad.Free
import Data.List
main :: IO ()
main = return ()
call :: Service -> App ()
call _ =
do
(AppState { arguments }) <- get
let params@(ServerParams { ssl, domain, directory, serverType, email }) = toServerParams arguments
-- Turn SSL off at first, because we have not yet received a certificate
let content = show (params { ssl = False, port = "80" })
config = "/etc/nginx/"
mainConfig = "/etc/nginx/nginx.conf"
parent = config </> "serverman-configs"
path = parent </> domain
targetDir = directory
createCert path cmd = do
result <- executeRoot cmd ["certonly", "--webroot", "--webroot-path", directory, "-d", domain, "--email", email, "--agree-tos", "-n"] "" False
case result of
Left _ -> if cmd == "letsencrypt" then createCert path "certbot" else return ()
Right stdout -> do
liftIO $ putStrLn stdout
when (not ("error" `isInfixOf` stdout)) $ do
liftIO $ writeFile path (show params)
liftIO . wait =<< restart
return ()
liftIO $ do
createDirectoryIfMissing True targetDir
createDirectoryIfMissing True parent
writeIncludeStatementIfMissing mainConfig parent
when ssl $ do
let sslPath = config </> "ssl.conf"
writeFileIfMissing sslPath nginxSSL
putStrLn $ "wrote ssl configuration to " ++ sslPath
writeFile path content
putStrLn $ "wrote your configuration file to " ++ path
liftIO . wait =<< restart
when ssl $ do
let dhparamPath = "/etc/ssl/certs/dhparam.pem"
dhExists <- liftIO $ doesFileExist dhparamPath
when (not dhExists) $ do
dhparam <- liftedAsync $ executeRoot "openssl" ["dhparam", "-out", dhparamPath, "2048"] "" True
liftIO $ wait dhparam
return ()
case serverType of
Static -> do
letsencrypt <- liftedAsync $ createCert path "letsencrypt"
liftIO $ wait letsencrypt
return ()
_ -> liftIO $ do
putStrLn $ "you should use letsencrypt to create a certificate for your domain"
putStrLn $ "and put it in /etc/letsencrypt/live/" ++ domain ++ "/fullchain.pem"
putStrLn $ "my suggestion is running this command:"
putStrLn $ "sudo letsencrypt certonly --webroot --webroot-path <YOUR_APPLICATION_DIRECTORY> -d " ++ domain
liftIO $ putStrLn $ "for more information, see: https://certbot.eff.org/"
return ()
where
restart = liftedAsync $ do
result <- restartService "nginx"
case result of
Left err -> return ()
Right _ ->
liftIO $ putStrLn $ "restarted nginx"
writeIncludeStatementIfMissing path target = do
content <- readFile path
let statement = "include " ++ target ++ "/*;"
when (not (statement `isInfixOf` content)) $ do
let newContent = appendAfter content "http {" (indent . indent $ statement)
writeFile path newContent
nginxSSL = "# from https://cipherli.st/\n\
\# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html\n\
\\n\
\ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n\
\ssl_prefer_server_ciphers on;\n\
\ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';\n\
\ssl_ecdh_curve secp384r1;\n\
\ssl_session_cache shared:SSL:10m;\n\
\ssl_session_tickets off;\n\
\ssl_stapling on;\n\
\ssl_stapling_verify on;\n\
\resolver 8.8.8.8 8.8.4.4 valid=300s;\n\
\resolver_timeout 5s;\n\
\# Disable preloading HSTS for now. You can use the commented out header line that includes\n\
\# the 'preload' directive if you understand the implications.\n\
\#add_header Strict-Transport-Security 'max-age=63072000; includeSubdomains; preload';\n\
\add_header Strict-Transport-Security 'max-age=63072000; includeSubdomains';\n\
\add_header X-Frame-Options DENY;\n\
\add_header X-Content-Type-Options nosniff;\n\
\\n\
\ssl_dhparam /etc/ssl/certs/dhparam.pem;\n"

BIN
services/nginx/src/Main.o Normal file

Binary file not shown.

View File

@ -0,0 +1,76 @@
{-# LANGUAGE NamedFieldPuns #-}
module Types ( ServerType (..)
, ServerParams (..)
, toServerParams) where
import System.Serverman.Types
import System.Serverman.Utils
import Data.Default.Class
toServerParams :: [(String, Maybe String)] -> ServerParams
toServerParams (("directory", Just value):xs) = (toServerParams xs) { directory = value, serverType = Static }
toServerParams (("domain", Just value):xs) = (toServerParams xs) { domain = value }
toServerParams (("port", Just value):xs) = (toServerParams xs) { port = value }
toServerParams (("forward", Just value):xs) = (toServerParams xs) { forward = value, serverType = PortForwarding }
toServerParams (("email", Just value):xs) = (toServerParams xs) { email = value }
toServerParams (("ssl", Nothing):xs) = (toServerParams xs) { ssl = True }
toServerParams _ = def
data ServerType = Static | PortForwarding deriving (Show, Eq)
data ServerParams = ServerParams { directory :: FilePath
, domain :: String
, port :: String
, forward :: String
, email :: String
, ssl :: Bool
, serverType :: ServerType
} deriving (Eq)
instance Default ServerParams where
def = ServerParams { directory = "/var/www"
, domain = "localhost"
, port = "80"
, forward = ""
, email = ""
, ssl = False
, serverType = Static }
instance Show ServerParams where
show (ServerParams { directory, domain, port, forward, email, ssl, serverType }) =
let redirect
| ssl = block "server" $
semicolon $
keyvalue ([ ("listen", "80")
, ("listen", "[::]:80")
, ("server_name", domain)
, ("rewrite", "^ https://$server_name$request_uri? permanent")
]) " "
| otherwise = ""
https
| ssl = [ ("ssl_certificate", "/etc/letsencrypt/live/" ++ domain ++ "/fullchain.pem")
, ("ssl_certificate_key", "/etc/letsencrypt/live/" ++ domain ++ "/privkey.pem")
, ("include", "ssl.conf")]
| otherwise = []
listen = port ++ (if ssl then " ssl" else "")
base = [ ("server_name", domain)
, ("listen", listen)
, ("listen", "[::]:" ++ listen)
, ("index", "index.html index.html index.php")
] ++ https
in
case serverType of
Static ->
(block "server" $ keyvalue (base ++ [("root", directory)]) " ") ++ "\n" ++ redirect
PortForwarding ->
let proxyBlock = block "location /" $
semicolon $
keyvalue ([ ("proxy_pass", "http://127.0.0.1:" ++ forward)
, ("proxy_set_header", "X-Forwarded-Host $host")
, ("proxy_set_header", "X-Forwarded-Server $host")
, ("proxy_set_header", "X-Forwarded-For $proxy_add_x_forwarded_for")
]) " "
in (block "server" $ semicolon (keyvalue base " ") ++ proxyBlock) ++ "\n" ++ redirect

66
services/nginx/stack.yaml Normal file
View File

@ -0,0 +1,66 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# http://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-3.5
# resolver: nightly-2015-09-21
# resolver: ghc-7.10.2
# resolver: ghcjs-0.1.0_ghc-7.10.2
# resolver:
# name: custom-snapshot
# location: "./custom-snapshot.yaml"
resolver: lts-8.5
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# - location:
# git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# extra-dep: true
# subdirs:
# - auto-update
# - wai
#
# A package marked 'extra-dep: true' will only be built if demanded by a
# non-dependency (i.e. a user package), and its test suites and benchmarks
# will not be run. This is useful for tweaking upstream packages.
packages:
- '.'
# Dependency packages to be pulled from upstream that are not in the resolver
# (e.g., acme-missiles-0.3)
extra-deps: []
# Override default flag values for local packages and extra-deps
flags: {}
# Extra package databases containing global packages
extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=1.1"
#
# Override the architecture used by stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor