-
-
Notifications
You must be signed in to change notification settings - Fork 62
docs(getting-started): add solid start guide #351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,232 @@ | ||||||||||||||||||||
| --- | ||||||||||||||||||||
| title: "Solid Start" | ||||||||||||||||||||
| description: "Run GoModel in a production-ready way with a .env file, Docker, Docker Compose, or a native binary." | ||||||||||||||||||||
| icon: "shield-check" | ||||||||||||||||||||
| --- | ||||||||||||||||||||
|
|
||||||||||||||||||||
| This page shows a practical production baseline for GoModel. It assumes you | ||||||||||||||||||||
| will run GoModel behind HTTPS, keep secrets out of shell history, persist | ||||||||||||||||||||
| storage across restarts, and protect the gateway with a master key. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Production baseline | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Start with these decisions: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| | Area | Recommended default | | ||||||||||||||||||||
| | ---- | ------------------- | | ||||||||||||||||||||
| | Secrets | Put credentials in a `.env` file or your orchestrator's secret manager | | ||||||||||||||||||||
| | Authentication | Set `GOMODEL_MASTER_KEY` before exposing the gateway | | ||||||||||||||||||||
| | Logging | Use `LOG_FORMAT=json`; enable audit logging only with a retention policy | | ||||||||||||||||||||
| | Storage | Use SQLite for one instance, PostgreSQL or MongoDB for multiple instances | | ||||||||||||||||||||
| | Network | Terminate TLS at a reverse proxy or load balancer, then forward to GoModel | | ||||||||||||||||||||
| | Health checks | Use public `GET /health` from your proxy, load balancer, or process supervisor | | ||||||||||||||||||||
|
|
||||||||||||||||||||
| <Warning> | ||||||||||||||||||||
| Do not expose GoModel to the internet without `GOMODEL_MASTER_KEY`. When the | ||||||||||||||||||||
| key is empty, API routes are intentionally unprotected for local development. | ||||||||||||||||||||
| </Warning> | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Create a production .env file | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Create `/opt/gomodel/.env` or another path managed by your deployment system: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| PORT=8080 | ||||||||||||||||||||
| LOG_FORMAT=json | ||||||||||||||||||||
| LOG_LEVEL=info | ||||||||||||||||||||
| BODY_SIZE_LIMIT=10M | ||||||||||||||||||||
| GOMODEL_MASTER_KEY=replace-with-a-long-random-secret | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Provider credentials. Set only the providers you use. | ||||||||||||||||||||
| OPENAI_API_KEY=sk-... | ||||||||||||||||||||
| # ANTHROPIC_API_KEY=sk-ant-... | ||||||||||||||||||||
| # GEMINI_API_KEY=... | ||||||||||||||||||||
| # OPENROUTER_API_KEY=sk-or-... | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Storage: SQLite is fine for a single GoModel instance. | ||||||||||||||||||||
| STORAGE_TYPE=sqlite | ||||||||||||||||||||
| SQLITE_PATH=/app/data/gomodel.db | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Audit logs are optional. Keep bodies off unless you explicitly need them. | ||||||||||||||||||||
| LOGGING_ENABLED=true | ||||||||||||||||||||
| LOGGING_LOG_BODIES=false | ||||||||||||||||||||
| LOGGING_LOG_HEADERS=false | ||||||||||||||||||||
| LOGGING_RETENTION_DAYS=30 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Usage tracking is enabled by default; keep a retention window. | ||||||||||||||||||||
| USAGE_ENABLED=true | ||||||||||||||||||||
| USAGE_RETENTION_DAYS=90 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # Keep admin endpoints and dashboard enabled only when they are protected by auth | ||||||||||||||||||||
| # and reachable through your intended network path. | ||||||||||||||||||||
| ADMIN_ENDPOINTS_ENABLED=true | ||||||||||||||||||||
| ADMIN_UI_ENABLED=true | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
Comment on lines
+61
to
+65
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default admin surfaces to disabled in the production baseline. Setting Suggested doc patch-# Keep admin endpoints and dashboard enabled only when they are protected by auth
-# and reachable through your intended network path.
-ADMIN_ENDPOINTS_ENABLED=true
-ADMIN_UI_ENABLED=true
+# Keep admin endpoints/dashboard disabled by default in production.
+# Enable only when needed, with explicit network and auth controls.
+ADMIN_ENDPOINTS_ENABLED=false
+ADMIN_UI_ENABLED=false📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| Protect the file on the host: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| sudo chown root:root /opt/gomodel/.env | ||||||||||||||||||||
| sudo chmod 600 /opt/gomodel/.env | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| <Tip> | ||||||||||||||||||||
| SQLite uses sidecar files such as `gomodel.db-wal` and `gomodel.db-shm`, so | ||||||||||||||||||||
| mount a directory, not only the `.db` file. | ||||||||||||||||||||
| </Tip> | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Run with Docker | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Use Docker when you want the smallest operational surface. Mount durable | ||||||||||||||||||||
| storage and load secrets from the `.env` file: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| sudo mkdir -p /opt/gomodel/data | ||||||||||||||||||||
| sudo chown 65532:65532 /opt/gomodel/data | ||||||||||||||||||||
|
|
||||||||||||||||||||
| docker run -d --name gomodel \ | ||||||||||||||||||||
| --restart unless-stopped \ | ||||||||||||||||||||
| --env-file /opt/gomodel/.env \ | ||||||||||||||||||||
| -p 127.0.0.1:8080:8080 \ | ||||||||||||||||||||
| -v /opt/gomodel/data:/app/data \ | ||||||||||||||||||||
| enterpilot/gomodel | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Bind to `127.0.0.1` when a reverse proxy on the same host terminates HTTPS. If | ||||||||||||||||||||
| GoModel sits behind a cloud load balancer or another container network, publish | ||||||||||||||||||||
| the port according to that network boundary instead. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Run with Docker Compose | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Use Compose when you also run Redis, PostgreSQL, MongoDB, Prometheus, or a | ||||||||||||||||||||
| reverse proxy on the same host. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```yaml | ||||||||||||||||||||
| services: | ||||||||||||||||||||
| gomodel: | ||||||||||||||||||||
| image: enterpilot/gomodel | ||||||||||||||||||||
| restart: unless-stopped | ||||||||||||||||||||
| env_file: | ||||||||||||||||||||
| - /opt/gomodel/.env | ||||||||||||||||||||
| ports: | ||||||||||||||||||||
| - "127.0.0.1:8080:8080" | ||||||||||||||||||||
| volumes: | ||||||||||||||||||||
| - /opt/gomodel/data:/app/data | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Start or update the service: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| docker compose up -d | ||||||||||||||||||||
| docker compose logs -f gomodel | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| For multi-instance deployments, switch storage to PostgreSQL or MongoDB: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| STORAGE_TYPE=postgresql | ||||||||||||||||||||
| POSTGRES_URL=postgres://gomodel:strong-password@postgres:5432/gomodel | ||||||||||||||||||||
| POSTGRES_MAX_CONNS=10 | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Run as a native binary | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Use a native binary when you already manage services with systemd and want to | ||||||||||||||||||||
| avoid a container runtime. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Build the binary: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| make build | ||||||||||||||||||||
| sudo install -m 0755 bin/gomodel /usr/local/bin/gomodel | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| For a native binary, use a host filesystem path for SQLite: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| # /opt/gomodel/.env | ||||||||||||||||||||
| PORT=8080 | ||||||||||||||||||||
| LOG_FORMAT=json | ||||||||||||||||||||
| GOMODEL_MASTER_KEY=replace-with-a-long-random-secret | ||||||||||||||||||||
| OPENAI_API_KEY=sk-... | ||||||||||||||||||||
| STORAGE_TYPE=sqlite | ||||||||||||||||||||
| SQLITE_PATH=/var/lib/gomodel/gomodel.db | ||||||||||||||||||||
| LOGGING_ENABLED=true | ||||||||||||||||||||
| LOGGING_LOG_BODIES=false | ||||||||||||||||||||
| LOGGING_RETENTION_DAYS=30 | ||||||||||||||||||||
|
Comment on lines
+167
to
+169
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This native-binary sample enables audit logging and disables body logging, but it omits
Suggested change
Context Used: CLAUDE.md (source) |
||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Create a systemd service: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```ini | ||||||||||||||||||||
| [Unit] | ||||||||||||||||||||
| Description=GoModel AI gateway | ||||||||||||||||||||
| After=network-online.target | ||||||||||||||||||||
| Wants=network-online.target | ||||||||||||||||||||
|
|
||||||||||||||||||||
| [Service] | ||||||||||||||||||||
| Type=simple | ||||||||||||||||||||
| User=gomodel | ||||||||||||||||||||
| Group=gomodel | ||||||||||||||||||||
| WorkingDirectory=/opt/gomodel | ||||||||||||||||||||
| EnvironmentFile=/opt/gomodel/.env | ||||||||||||||||||||
| ExecStart=/usr/local/bin/gomodel | ||||||||||||||||||||
| Restart=always | ||||||||||||||||||||
| RestartSec=5 | ||||||||||||||||||||
| NoNewPrivileges=true | ||||||||||||||||||||
| PrivateTmp=true | ||||||||||||||||||||
|
|
||||||||||||||||||||
| [Install] | ||||||||||||||||||||
| WantedBy=multi-user.target | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Enable it: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| sudo useradd --system --home /var/lib/gomodel --shell /usr/sbin/nologin gomodel | ||||||||||||||||||||
| sudo mkdir -p /var/lib/gomodel /opt/gomodel | ||||||||||||||||||||
| sudo chown gomodel:gomodel /var/lib/gomodel | ||||||||||||||||||||
| sudo systemctl daemon-reload | ||||||||||||||||||||
| sudo systemctl enable --now gomodel | ||||||||||||||||||||
| sudo journalctl -u gomodel -f | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Verify the deployment | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Check liveness: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| curl -fsS http://127.0.0.1:8080/health | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Check authenticated API access: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| curl -fsS http://127.0.0.1:8080/v1/models \ | ||||||||||||||||||||
| -H "Authorization: Bearer replace-with-a-long-random-secret" | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Send a smoke-test request: | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ```bash | ||||||||||||||||||||
| curl -fsS http://127.0.0.1:8080/v1/chat/completions \ | ||||||||||||||||||||
| -H "Authorization: Bearer replace-with-a-long-random-secret" \ | ||||||||||||||||||||
| -H "Content-Type: application/json" \ | ||||||||||||||||||||
| -d '{ | ||||||||||||||||||||
| "model": "gpt-4o-mini", | ||||||||||||||||||||
| "messages": [{"role": "user", "content": "Reply with ok."}] | ||||||||||||||||||||
| }' | ||||||||||||||||||||
| ``` | ||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Operational notes | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - Put HTTPS, rate limits, IP allowlists, and request timeouts in your reverse | ||||||||||||||||||||
| proxy or load balancer. | ||||||||||||||||||||
| - Keep `PPROF_ENABLED=false` in production unless you expose it only on a | ||||||||||||||||||||
| trusted internal network during an investigation. | ||||||||||||||||||||
| - Keep `LOGGING_LOG_BODIES=false` unless your data handling policy allows full | ||||||||||||||||||||
| prompt and response capture. | ||||||||||||||||||||
| - Use [Configuration](/advanced/configuration) for the full environment | ||||||||||||||||||||
| variable reference. | ||||||||||||||||||||
| - Use [Prometheus Metrics](/guides/prometheus-metrics) if you want metrics | ||||||||||||||||||||
| scraping; it is currently experimental. | ||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This production sample enables
ADMIN_UI_ENABLED=truewhile saying the dashboard should be kept enabled only when protected by auth. In the server,/admin/dashboardand its static assets skip GoModel auth whenever the dashboard is enabled, even whenGOMODEL_MASTER_KEYis set. An operator who copies this baseline can expose the dashboard publicly behind HTTPS while believing the master key protects it. The production default should either disable the dashboard UI or explicitly require proxy/network auth before enabling it.Context Used: CLAUDE.md (source)