# [GoServ](https://git.coolaj86.com/coolaj86/goserv) !["golang gopher with goggles"](https://i.imgur.com/S2nhiRK.jpg) > Boilerplate for how I like to write a backend web service ## Build #### Goreleaser See Local-only ```bash goreleaser --snapshot --skip-publish --rm-dist ``` Publish ```bash # Get a token at https://github.com/settings/tokens export GITHUB_TOKEN=xxxxxxx # Remove --snapshot to error on non-clean releases goreleaser --snapshot --rm-dist ``` The platform, publish URL, and token file can be changed in `.goreleaser.yml`: ```yml env_files: gitea_token: ~/.config/goreleaser/gitea_token gitea_urls: api: https://try.gitea.io/api/v1/ ``` #### Manually ```bash git clone ssh://gitea@git.coolaj86.com:22042/coolaj86/goserv.git ./goserv pushd ./goserv bash ./examples/build.sh ``` ```bash export GOFLAGS="-mod=vendor" go mod tidy go mod vendor go generate -mod=vendor ./... go build -mod=vendor -o dist/goserv . ``` To build for another platform (such as Raspberry Pi) set `GOOS` and GOARCH`: ```bash GOOS=linux GOARCH=arm64 go build -mod=vendor -o dist/goserv-linux-arm64 . ``` #### Run ```bash ./dist/goserv run --listen :3000 --trust-proxy --serve-path ./overrides ``` ## Examples and Config Templates The example files are located in `./examples` - Caddyfile (web server config) - .env (environment variables) - build.sh ```bash export BASE_URL=https://example.com ``` ### Authentication You can use an OIDC provider or sign your own tokens. ```bash go install -mod=vendor git.rootprojects.org/root/keypairs/cmd/keypairs # Generate a keypair keypairs gen -o key.jwk.json --pub pub.jwk.json ``` Create an Admin token: ```bash # Sign an Admin token echo '{ "sub": "random_ppid", "email": "me@example.com", "iss": "'"${BASE_URL}"'" }' \ > admin.claims.json keypairs sign --exp 1h ./key.jwk.json ./admin.claims.json > admin.jwt.txt 2> admin.jws.json # verify the Admin token keypairs verify ./pub.jwk.json ./admin.jwt.txt ``` Create a User token: ```bash # Sign a User token echo '{ "sub": "random_ppid", "email": "me@example.com", "iss": "'"${BASE_URL}"'" }' \ > user.claims.json keypairs sign --exp 1h ./key.jwk.json ./user.claims.json > user.jwt.txt 2> user.jws.json # verify the User token keypairs verify ./pub.jwk.json ./user.jwt.txt ``` **Impersonation** can be accomplished by appending the token `sub` (aka PPID) to the url as `?user_id=`. ## REST API All routes require authentication, except for those at `/api/public`. ```txt Authentication: Bearer ``` Here's the API, in brief: Base URL looks like `https://example.com/api`. ```txt # Demo Mode Only DELETE /public/reset Drop database and re-initialize # Public GET /public/ping Health Check POST /public/setup <= (none) Bootstrap # Admin-only GET /admin/ping (authenticated) Health Check # User GET /user/ping (authenticated) Health Check ``` When you `GET` anything, it will be wrapped in the `result`. #### Bootstrapping The first user to hit the `/api/setup` endpoint will be the **admin**: ```bash export TOKEN=$(cat admin.jwt.txt) ``` ```bash curl -X POST "${BASE_URL}/api/public/setup" -H "Authorization: Bearer ${TOKEN}" ``` Then the setup endpoint will be disabled: ```bash curl -X POST "${BASE_URL}/api/public/setup" -H "Authorization: Bearer ${TOKEN}" ``` ## GoDoc If the documentation is not public hosted you can view it with GoDoc: ```bash godoc --http :6060 ``` - - - You can see abbreviated documentation with `go`'s built-in `doc`, for example: ```bash go doc git.example.com/example/goserv/internal/api ``` ## Test Create a test database. It must have `test` in the name. ```sql DROP DATABASE "goserv_test"; CREATE DATABASE "goserv_test"; ``` Run the tests: ```bash export TEST_DATABASE_URL='postgres://postgres:postgres@localhost:5432/goserv_test' go test -mod=vendor ./... ``` ## 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 Sheets 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 ## Licenses Copyright 2020 The GoServ Authors. All rights reserved. ### Exceptions - `countries.json` LGPL, taken from - `flags.json` MIT, taken from These are probably also in the Public Domain. \ (gathering the official data from any source would yield the same dataset)