+ These steps require Docker. + Open a terminal and verify it is installed by running: +
+docker --version
+ + If Docker is not installed, you will see something like docker: command not found. In that case, install Docker first and come back here. +
+Pull the image:
+docker pull ghcr.io/bit8bytes/gearberg
+ Try starting the server but it will fail with a clear error:
+docker run -p 8080:8080 ghcr.io/bit8bytes/gearberg serve
+ error: -base-url is required (e.g. -base-url https://gearberg.example.com)
+ + The app will not start without a base URL. + The base URL is used e.g. for password reset links or OIDC callbacks. + Gearberg reports all configuration errors on startup so you can fix them before the server starts. +
+
+ Add the -base-url flag to start the server:
+
docker run -p 8080:8080 ghcr.io/bit8bytes/gearberg serve \
+ -base-url https://gearberg.example.com
+ + Now, the server is running and you can access the web interface at + http://localhost:8080. + You can stop the server by pressing Ctrl + C in the terminal. +
++ Visit http://localhost:8080/signup + to create your first account. The first user to sign up becomes the org admin. +
++ The previous code does not persist data across restarts, so any changes you make will be lost when the container is stopped or removed. + To avoid this, mount a named volume so data persists across restarts: +
+docker run -p 8080:8080 -v gearberg-data:/data \
+ ghcr.io/bit8bytes/gearberg serve \
+ -base-url https://gearberg.example.com
+ Gearberg is up and running and ready to use for testing. For actual deployment, see Docker Compose.
++ Gearberg is configured via command-line flags and environment variables. Flags take precedence over env vars. + All configuration errors are reported on startup and the server will not start with invalid or missing required values. +
++ To check your configuration without starting the server, run: +
+docker run -p 8080:8080 ghcr.io/bit8bytes/gearberg check \
+ -base-url https://gearberg.example.com
+ Use flags for non-sensitive settings (e.g. log-level):
+docker run -p 8080:8080 ghcr.io/bit8bytes/gearberg serve \
+ -base-url https://gearberg.example.com \
+ -log-level info
+ Use environment variables for secrets because flags appear in process listings and shell history:
+docker run -p 8080:8080 \
+ -e SMTP_PASSWORD=secret \
+ ghcr.io/bit8bytes/gearberg serve \
+ -base-url https://gearberg.example.com \
+ -smtp-host smtp.example.com \
+ -smtp-username gearberg@example.com \
+ -smtp-from gearberg@example.com
+ + See All Flags & Env Vars for the complete reference. +
++ By default, Gearberg uses email/password login which does not require any configuration. To extend it with SSO, configure one or more OIDC providers. + Currently, only the Authentik provider is supported. +
+ +OIDC_<NAME>_PROVIDER=name,issuer=URL,client-id=ID,client-secret=SECRET
+
+ <NAME> becomes the provider name.
+ Repeat the variable for multiple providers. Flags take precedence over env vars.
+ For authentik, the env var would look like this: OIDC_AUTHENTIK_PROVIDER.
+
+ Gearberg uses SMTP to send transactional emails such as password reset links and invitations.
+ SMTP is optional. When -smtp-host is omitted,
+ emails are silently discarded and no mail is sent.
+
+ Pass the password via the SMTP_PASSWORD env var and not the flag.
+
docker run -p 8080:8080 \
+ -v gearberg-data:/data \
+ -e SMTP_PASSWORD=secret \
+ ghcr.io/bit8bytes/gearberg serve \
+ -smtp-host smtp.example.com \
+ -smtp-username gearberg@example.com \
+ -smtp-from gearberg@example.com
+
+ -smtp-port defaults to 587.
+
+ The recommended way to run Gearberg in production is via the official Docker image using Docker Compose. +
+For this, we recommend creating a .env file next to compose.yaml and fill in your secrets:
printf 'OIDC_AUTHENTIK_PROVIDER=\nSMTP_PASSWORD=\n' > .env
+ OIDC_AUTHENTIK_PROVIDER=authentik,issuer=https://auth.example.com/application/o/gearberg/,client-id=<your-client-id>,client-secret=<your-client-secret>
+ SMTP_PASSWORD=<your-smtp-password>
+ Then create compose.yaml, replacing the highlighted line with your domain:
services:
+ gearberg:
+ image: ghcr.io/bit8bytes/gearberg
+ command: serve -base-url https://gearberg.example.com
+ restart: unless-stopped
+ ports:
+ - "8080:8080"
+ volumes:
+ - gearberg-data:/data
+ environment:
+ OIDC_AUTHENTIK_PROVIDER: "${OIDC_AUTHENTIK_PROVIDER}"
+ SMTP_PASSWORD: "${SMTP_PASSWORD}"
+ env_file:
+ - .env
+
+ volumes:
+ gearberg-data:
+ Start Gearberg in the background:
+docker compose up -d
+ Add a reverse proxy for HTTPS
+For production, place a reverse proxy in front of Gearberg to terminate TLS. Popular options include
+ Caddy (automatic HTTPS with zero config),
+ Traefik (Docker-native with Let's Encrypt), and
+ nginx (battle-tested, manual cert management).
+ Point whichever you choose at localhost:8080.
+
| Flag | +Env var | +Default | +Description | +
|---|---|---|---|
-base-url |
+ — | +required | +Public base URL | +
-db-dsn |
+ DB_DSN |
+ file:/data/gearberg.db |
+ Database DSN | +
-storage-dsn |
+ STORAGE_DSN |
+ file:///data/uploads |
+ Storage backend DSN | +
-port |
+ — | +8080 |
+ Port to listen on | +
-log-level |
+ — | +error |
+ debug, info, warn, error |
+
-tls-mode |
+ — | +off |
+ off or local |
+
-tls-cert-path |
+ — | +— | +TLS certificate (required with -tls-mode=local) |
+
-tls-key-path |
+ TLS_KEY_PATH |
+ — | +TLS key (required with -tls-mode=local) |
+
-max-orgs |
+ — | +1 |
+ Maximum number of orgs | +
-max-categories |
+ — | +25 |
+ Equipment categories per org | +
-max-manufacturers |
+ — | +100 |
+ Manufacturers per org | +
-max-locations |
+ — | +100 |
+ Locations per org | +
-max-storage-bytes |
+ — | +1073741824 (1 GiB) |
+ Storage per org | +
-oidc-provider |
+ OIDC_<NAME>_PROVIDER |
+ — | +OIDC provider (repeatable) | +
-smtp-host |
+ — | +- | +SMTP hostname | +
-smtp-port |
+ — | +587 |
+ SMTP port | +
-smtp-username |
+ — | +— | +SMTP username | +
-smtp-password |
+ SMTP_PASSWORD |
+ — | +SMTP password | +
-smtp-from |
+ — | +— | +From address | +
docker run -it -p 8080:8080 nixos/nix \
- nix --extra-experimental-features "nix-command flakes" \
- run github:bit8bytes/gearberg -- serve
+ docker run -p 8080:8080 ghcr.io/bit8bytes/gearberg serve \
+ -base-url http://localhost:8080
diff --git a/internal/templates/pages/pages.go b/internal/templates/pages/pages.go
index 2d6639d..d17738d 100644
--- a/internal/templates/pages/pages.go
+++ b/internal/templates/pages/pages.go
@@ -41,11 +41,14 @@ func newPage(file string, layout layouts.Layout) Page {
return p
}
-// Pages.
-var (
- // Landing is the public landing page.
- Landing = newPage("pages/landing.tmpl", layouts.Landing)
+// Landing is the public landing page.
+var Landing = newPage("pages/landing.tmpl", layouts.Landing)
+
+// Docs is the public docs page.
+var Docs = newPage("pages/docs.tmpl", layouts.Docs)
+// Web app pages.
+var (
// Orgs is the org selector page.
Orgs = newPage("pages/orgs/index.tmpl", layouts.Center)
// OrgsNew is the create-org form page.
diff --git a/internal/templates/partials/docs-footer.tmpl b/internal/templates/partials/docs-footer.tmpl
new file mode 100644
index 0000000..86e6423
--- /dev/null
+++ b/internal/templates/partials/docs-footer.tmpl
@@ -0,0 +1,13 @@
+{{ define "docs-footer" }}
+
+{{ end }}
diff --git a/internal/templates/partials/docs-header.tmpl b/internal/templates/partials/docs-header.tmpl
new file mode 100644
index 0000000..43fa4b0
--- /dev/null
+++ b/internal/templates/partials/docs-header.tmpl
@@ -0,0 +1,17 @@
+{{ define "docs-header" }}
+
+{{ end }}
diff --git a/internal/templates/partials/docs-sidebar.tmpl b/internal/templates/partials/docs-sidebar.tmpl
new file mode 100644
index 0000000..567a2b6
--- /dev/null
+++ b/internal/templates/partials/docs-sidebar.tmpl
@@ -0,0 +1,18 @@
+{{ define "docs-sidebar" }}
+
+{{ end }}
\ No newline at end of file
diff --git a/internal/templates/partials/landing-header.tmpl b/internal/templates/partials/landing-header.tmpl
index 74bd617..2278903 100644
--- a/internal/templates/partials/landing-header.tmpl
+++ b/internal/templates/partials/landing-header.tmpl
@@ -5,7 +5,16 @@