diff --git a/README.md b/README.md index 3c673ca..aafef2b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,96 @@ go build -mod=vendor . ./goserv run --listen :3000 --serve-path ./overrides ``` +## Eamples and Config Templates + +The example files are located in `./examples` + +- Caddyfile (web server config) +- .env (environment variables) +- build.sh + +## Dependencies + +This setup can be run on a VPS, such as Digital Ocean, OVH, or Scaleway +for \$5/month with minimal dependencies: + +- VPS +- Caddy +- PostgreSQL +- Serviceman + +**Mac**, **Linux**: + +```bash +curl -fsS https://webinstall.dev | bash +export PATH="$HOME:/.local/bin:$PATH" +``` + +```bash +webi caddy serviceman postgres +``` + +### VPS Setup + +You should have a domain pointing to a VPS and create a user account named `app` +(because that's a common convention). This script will create an `app` user, +copying the `authorized_keys` from the root account. + +```bash +my_vps='example.com' +ssh root@"$my_vps" 'curl -sS https://webinstall.dev/ssh-adduser | bash' +``` + +You can then login as a normal user. + +```bash +ssh app@"$my_vps" +``` + +It is now safe to disable the root account. + +### Caddy (Automatic HTTPS Server) + +```bash +curl -fsS https://webinstall.dev/caddy | bash +``` + +You can start Caddy as a system service under the app user like this: + +```bash +sudo setcap 'cap_net_bind_service=+ep' "$(readlink $(command -v caddy))" + +sudo env PATH="$PATH" \ + serviceman add --name caddy --username app \ + caddy run --config ./Caddyfile +``` + +See the Cheat Sheet at https://webinstall.dev/caddy +and https://webinstall.dev/serviceman + +### PostgreSQL (Database) + +```bash +curl -fsS https://webinstall.dev/postgres | bash +``` + +You can start Postgres as a system service under the app user like this: + +```bash +sudo env PATH="$PATH" \ + serviceman add --name postgres --username app -- \ + postgres -D /home/app/.local/share/postgres/var -p 5432 +``` + +Username and password are set to 'postgres' by default: + +```bash +psql 'postgres://postgres:postgres@localhost:5432/postgres' +``` + +See the Cheat Sheets at https://webinstall.dev/postgres +and https://webinstall.dev/serviceman + ## License Copyright 2020. All rights reserved. diff --git a/examples/Caddyfile b/examples/Caddyfile new file mode 100644 index 0000000..85a8308 --- /dev/null +++ b/examples/Caddyfile @@ -0,0 +1,31 @@ +# redirect www to bare domain +www.example.com { + redir https://example.com{uri} permanent +} + +example.com { + # log to stdout, which is captured by journalctl + log { + output stdout + format console + } + + # turn on standard streaming compression + encode gzip zstd + + # reverse proxy /api to :3000 + reverse_proxy /api/* localhost:3000 + + # serve static files from public folder, but not /api + @notApi { + file { + try_files {path} {path}/ {path}/index.html + } + not path /api/* + } + route { + rewrite @notApi {http.matchers.file.relative} + } + root * /srv/example.com/public/ + file_server +} diff --git a/examples/build.sh b/examples/build.sh new file mode 100644 index 0000000..5ec1442 --- /dev/null +++ b/examples/build.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e +set -u + +export GOFLAGS="-mod=vendor" +go mod tidy +go mod vendor +go generate -mod=vendor ./... +go build -mod=vendor . + diff --git a/examples/dotenv b/examples/dotenv new file mode 100644 index 0000000..13fc9d0 --- /dev/null +++ b/examples/dotenv @@ -0,0 +1,2 @@ +PORT="3000" +#LISTEN=":3000" diff --git a/main.go b/main.go index f0c8b9b..27f8497 100644 --- a/main.go +++ b/main.go @@ -38,6 +38,8 @@ func ver() { fmt.Printf("%s v%s %s (%s)\n", name, version, commit[:7], date) } +var defaultAddr = ":3000" + type runOptions struct { listen string trustProxy bool @@ -53,16 +55,15 @@ var dbURL string func init() { runOpts = runOptions{} runFlags = flag.NewFlagSet("run", flag.ExitOnError) - runFlags.StringVar(&runOpts.listen, "listen", ":3000", "the address and port on which to listen") + runFlags.StringVar( + &runOpts.listen, "listen", "", + "the address and port on which to listen (default \""+defaultAddr+"\")") runFlags.BoolVar(&runOpts.trustProxy, "trust-proxy", false, "trust X-Forwarded-For header") runFlags.BoolVar(&runOpts.compress, "compress", true, "enable compression for text,html,js,css,etc") runFlags.StringVar(&runOpts.static, "serve-path", "", "path to serve, falls back to built-in web app") runFlags.StringVar( - &dbURL, - "db-url", - "postgres://postgres:postgres@localhost:5432/postgres", - "database (postgres) connection url", - ) + &dbURL, "db-url", "postgres://postgres:postgres@localhost:5432/postgres", + "database (postgres) connection url") } func main() { @@ -94,6 +95,17 @@ func main() { initFlags.Parse(args[2:]) case "run": runFlags.Parse(args[2:]) + if "" == runOpts.listen { + listen := os.Getenv("LISTEN") + port := os.Getenv("PORT") + if len(listen) > 0 { + runOpts.listen = listen + } else if len(port) > 0 { + runOpts.listen = "127.0.0.1:" + port + } else { + runOpts.listen = defaultAddr + } + } serve() default: usage()