Šéļƒ-Ĥöšţîñĝ
Ŕüñ ýöüŕ öŵñ Bowrain îñšţàñçé ŵîţĥ Đöçķéŕ. À đéþļöýḿéñţ îš à ƒéŵ çööþéŕàţîñĝ šéŕṽîçéš:
- bowrain-šéŕṽéŕ: ţĥé ŔÉŠŢ + ĝŔÞÇ ÀÞÎ.
- bowrain-ŵöŕķéŕ: ţĥé àšýñç ŵöŕķéŕ; îñĝéšţš þüšĥéš àñđ ŕüñš ţĥé đŕàƒţîñĝ ĵöƃš à ŕüñ éñǫüéüéš àĝàîñšţ àñ üþšţŕéàḿ ÀÎ þŕöṽîđéŕ.
- ÞöšţĝŕéŠǪĻ: ţĥé àüţĥöŕîţàţîṽé šţöŕé (þŕöĵéçţš, ƃļöçķš, ŵöŕķšþàçéš, üšéŕš, ĵöƃš). Ţĥé šéŕṽéŕ ŕéǫüîŕéš ÞöšţĝŕéŠǪĻ; ţĥéŕé îš ñö ŠǪĻîţé öŕ ƒîļé ƃàçķéñđ.
- À ĵöƃ ǫüéüé (Àḿàžöñ ŠǪŠ, öŕ àñ ŠǪŠ-çöḿþàţîƃļé ƃŕöķéŕ šüçĥ àš ÉļàšţîçḾǪ) àñđ à Ŕéđîš îñšţàñçé ƒöŕ ţĥé éṽéñţ ƃüš (Ŕéđîš Šţŕéàḿš), šĥàŕéđ ƃý ţĥé šéŕṽéŕ àñđ ŵöŕķéŕ. Þüšĥ þŕöçéššîñĝ îš àšýñçĥŕöñöüš: ţĥé šéŕṽéŕ éñǫüéüéš, ţĥé ŵöŕķéŕ îñĝéšţš àñđ đŕàƒţš.
- Ƃļöƃ šţöŕàĝé ƒöŕ îñ-ƒļîĝĥţ þüšĥ þàýļöàđš: à ļöçàļ đîŕéçţöŕý šĥàŕéđ ƃý ţĥé šéŕṽéŕ àñđ ŵöŕķéŕ, öŕ àñ Š3 ƃüçķéţ (ḾîñÎÖ ƒöŕ à ļöçàļ šţàçķ).
- bowrain-ŵéƃ: ţĥé šţàţîç ŵéƃ ÜÎ, šéŕṽéđ àš îţš öŵñ çöñţàîñéŕ.
- Àñ ÖÎĐÇ îđéñţîţý þŕöṽîđéŕ (ƒöŕ éẋàḿþļé Ķéýçļöàķ) àñđ àñ ŠḾŢÞ šéñđéŕ.
À ŕéṽéŕšé þŕöẋý ŕöüţéš /api + ĝŔÞÇ ţö ţĥé šéŕṽéŕ àñđ éṽéŕýţĥîñĝ éļšé ţö ţĥé ŵéƃ ÜÎ.
Ǫüîçķ Šţàŕţ
Ţĥé ŕéþöšîţöŕý šĥîþš à çöḿþļéţé ŕéƒéŕéñçé šţàçķ àţ
bowrain/deploy/docker/compose.yaml:
Ţŕàéƒîķ, ÞöšţĝŕéŠǪĻ, ÉļàšţîçḾǪ (ŠǪŠ-çöḿþàţîƃļé ĵöƃ ǫüéüé), Ŕéđîš, ţĥé šéŕṽéŕ,
ţĥé ŵöŕķéŕ, àñđ ţĥé ŵéƃ ÜÎ, àļļ ƒŕöḿ þüƃļîšĥéđ îḿàĝéš. Çöþý îţ ţöĝéţĥéŕ ŵîţĥ
îţš šîƃļîñĝ traefik.yml, šéţ ţĥé ŕéǫüîŕéđ ṽàļüéš, ţĥéñ šţàŕţ îţ:
docker compose -f deploy/docker/compose.yaml up -d
Ţĥé šţàçķ éẋþéçţš àñ éẋţéŕñàļ ÖÎĐÇ þŕöṽîđéŕ (šéé ÖÎĐÇ Þŕöṽîđéŕ Šéţüþ). Àţ ḿîñîḿüḿ, þŕöṽîđé:
POSTGRES_PASSWORD=... # database password
BOWRAIN_JWT_SECRET=$(openssl rand -base64 32) # JWT signing secret
BOWRAIN_OIDC_ISSUER_URL=... # your realm's issuer URL
BOWRAIN_OIDC_CLIENT_SECRET=... # the bowrain client's secret
BOWRAIN_APP_PUBLIC_URL=https://bowrain.example # the URL browsers use to reach Bowrain
# Drafting runs in the worker; configure an upstream AI provider:
BOWRAIN_PLATFORM_PROVIDER=gemini # or bedrock / openai / anthropic / ollama
BOWRAIN_PLATFORM_API_KEY=... # provider API key
Öñçé üþ, ţĥé ŵéƃ ÜÎ îš šéŕṽéđ ţĥŕöüĝĥ ţĥé þŕöẋý öñ þöŕţ 80; ñéŵ üšéŕš šéļƒ-ŕéĝîšţéŕ ţĥŕöüĝĥ ýöüŕ ÖÎĐÇ þŕöṽîđéŕ.
:::ţîþ Ƒöŕ à öñé-çöḿḿàñđ ļöçàļ šţàçķ ţĥàţ àļšö ƃüñđļéš Ķéýçļöàķ, ḾîñÎÖ àñđ Ḿàîļþîţ, ŵîţĥ ñö ÖÎĐÇ šéţüþ àñđ àñ öƒƒļîñé ÀÎ þŕöṽîđéŕ ƃý đéƒàüļţ, šéé ţĥé Îñšţàļļàţîöñ ĝüîđé. :::
Éñṽîŕöñḿéñţ Ṽàŕîàƃļéš
Šéŕṽéŕ (bowrain-server)
| Ṽàŕîàƃļé | Đéƒàüļţ | Đéšçŕîþţîöñ |
|---|---|---|
BOWRAIN_DATABASE_URL | ÞöšţĝŕéŠǪĻ çöññéçţîöñ šţŕîñĝ (postgres://…), ŕéǫüîŕéđ | |
BOWRAIN_JWT_SECRET | ĴŴŢ šîĝñîñĝ šéçŕéţ, ŕéǫüîŕéđ ƒöŕ àüţĥ | |
BOWRAIN_OIDC_ISSUER_URL | ÖÎĐÇ îššüéŕ ÜŔĻ (îñţéŕñàļ, ŕéàçĥàƃļé ƒŕöḿ ţĥé šéŕṽéŕ) | |
BOWRAIN_OIDC_PUBLIC_URL | Ƃŕöŵšéŕ-ƒàçîñĝ ÜŔĻ öƒ ţĥé îđéñţîţý þŕöṽîđéŕ, îƒ îţ đéŕš ƒŕöḿ ţĥé îššüéŕ ÜŔĻ | |
BOWRAIN_APP_PUBLIC_URL | Ţĥé ÜŔĻ ƃŕöŵšéŕš üšé ţö ŕéàçĥ Bowrain; šéţš ţĥé ÇÖŔŠ àñđ ŴéƃŠöçķéţ öŕîĝîñ àļļöŵļîšţš | |
BOWRAIN_FORCE_SECURE_COOKIES | true | Ḿàŕķš šéššîöñ çööķîéš Secure ŕéĝàŕđļéšš öƒ ţĥé ŕéǫüéšţ šçĥéḿé |
BOWRAIN_OIDC_CLIENT_ID | bowrain | ÖÎĐÇ çļîéñţ ÎĐ |
BOWRAIN_OIDC_CLIENT_SECRET | ÖÎĐÇ çļîéñţ šéçŕéţ | |
BOWRAIN_QUEUE_BACKEND | sqs šéļéçţš ţĥé ŠǪŠ ĵöƃ-ǫüéüé ƃàçķéñđ | |
SQS_ENDPOINT | ŠǪŠ éñđþöîñţ öṽéŕŕîđé ƒöŕ ÉļàšţîçḾǪ/ĻöçàļŠţàçķ; éḿþţý öñ ÀŴŠ | |
BOWRAIN_EVENT_BACKEND | redis ŕüñš ţĥé éṽéñţ ƃüš öñ Ŕéđîš Šţŕéàḿš | |
BOWRAIN_REDIS_URL | Ŕéđîš ÜŔĻ (éṽéñţ ƃüš, çàçĥîñĝ, šéššîöñ šţàţé) | |
BLOB_STORAGE_BACKEND | local | local öŕ s3 ƒöŕ îñ-ƒļîĝĥţ þüšĥ þàýļöàđš |
BLOB_STORAGE_LOCAL_DIR | Ļöçàļ ƃļöƃ đîŕéçţöŕý (šĥàŕéđ ŵîţĥ ţĥé ŵöŕķéŕ) | |
S3_BLOB_BUCKET | Ƃüçķéţ ƒöŕ ţĥé s3 ƃàçķéñđ (šéţţîñĝ îţ šéļéçţš s3) | |
BOWRAIN_SMTP_HOST | ŠḾŢÞ šéŕṽéŕ host:port ƒöŕ ţŕàñšàçţîöñàļ éḿàîļš | |
BOWRAIN_SMTP_FROM | Šéñđéŕ éḿàîļ àđđŕéšš ƒöŕ ţŕàñšàçţîöñàļ éḿàîļš | |
BOWRAIN_PORT | 8080 | ĤŢŢÞ þöŕţ ţö ļîšţéñ öñ |
BOWRAIN_HOST | 0.0.0.0 | Àđđŕéšš ţö ƃîñđ ţö |
Ŵöŕķéŕ (bowrain-worker)
| Ṽàŕîàƃļé | Đéšçŕîþţîöñ |
|---|---|
BOWRAIN_DATABASE_URL | Šàḿé ÞöšţĝŕéŠǪĻ çöññéçţîöñ šţŕîñĝ àš ţĥé šéŕṽéŕ |
BOWRAIN_QUEUE_BACKEND / SQS_ENDPOINT | Šàḿé ĵöƃ-ǫüéüé šéļéçţîöñ àš ţĥé šéŕṽéŕ (ţĥé ţŵö ḿüšţ àĝŕéé öñ ţĥé ƃŕöķéŕ) |
BOWRAIN_EVENT_BACKEND / BOWRAIN_REDIS_URL | Šàḿé éṽéñţ-ƃüš šéļéçţîöñ àš ţĥé šéŕṽéŕ |
LOCAL_BLOB_DIR | Ļöçàļ ƃļöƃ đîŕéçţöŕý; ḿüšţ þöîñţ àţ ţĥé šàḿé šĥàŕéđ ṽöļüḿé àš ţĥé šéŕṽéŕ'š BLOB_STORAGE_LOCAL_DIR |
BOWRAIN_PLATFORM_PROVIDER | ÀÎ þŕöṽîđéŕ ƒöŕ þļàţƒöŕḿ ĵöƃš: bedrock, gemini, openai, anthropic, ollama, öŕ demo (öƒƒļîñé) |
BOWRAIN_PLATFORM_API_KEY | Þŕöṽîđéŕ ÀÞÎ ķéý (öŕ à þŕöṽîđéŕ-šþéçîƒîç ṽàŕîàƃļé šüçĥ àš GEMINI_API_KEY) |
BOWRAIN_PLATFORM_MODEL | Đéƒàüļţ ḿöđéļ ƒöŕ ţĥé þŕöṽîđéŕ |
Ţĥé çöḿþļéţé ŕéƒéŕéñçé, îñçļüđîñĝ ţĥé Š3 éñđþöîñţ ṽàŕîàƃļéš ƒöŕ ḾîñÎÖ, îš öñ ţĥé Çöñƒîĝüŕàţîöñ þàĝé.
ÖÎĐÇ Þŕöṽîđéŕ Šéţüþ
Àñý ÖÎĐÇ-çöḿþļîàñţ îđéñţîţý þŕöṽîđéŕ ŵöŕķš ŵîţĥ bowrain-šéŕṽéŕ (Ķéýçļöàķ, Àüţĥ0, Öķţà, Ĝööĝļé, Àžüŕé ÀĐ, Đéẋ, àñđ öţĥéŕš). Ţĥé šéŕṽéŕ üšéš šţàñđàŕđ ÖÎĐÇ đîšçöṽéŕý ţö ŕéšöļṽé àüţĥöŕîžàţîöñ àñđ ţöķéñ éñđþöîñţš àüţöḿàţîçàļļý.
Ķéýçļöàķ (Ŕéçöḿḿéñđéđ)
Ķéýçļöàķ þŕöṽîđéš šéļƒ-ŕéĝîšţŕàţîöñ, éḿàîļ ṽéŕîƒîçàţîöñ, šöçîàļ ļöĝîñ ƒéđéŕàţîöñ, àñđ ƒîñé-ĝŕàîñéđ àççéšš çöñţŕöļ öüţ öƒ ţĥé ƃöẋ.
Ķéý çöñƒîĝüŕàţîöñ ƒöŕ ţĥé Ķéýçļöàķ çļîéñţ:
- Çļîéñţ ÎĐ:
bowrain - Çļîéñţ þŕöţöçöļ:
openid-connect - Àççéšš Ţýþé:
confidential(ŵîţĥ çļîéñţ šéçŕéţ) - Šţàñđàŕđ Ƒļöŵ Éñàƃļéđ:
true(àüţĥöŕîžàţîöñ çöđé ƒļöŵ) - Ṽàļîđ Ŕéđîŕéçţ ÜŔΚ:
https://your-domain.com/api/v1/auth/callback - Ŵéƃ Öŕîĝîñš:
https://your-domain.com
Éñàƃļé šéļƒ-ŕéĝîšţŕàţîöñ îñ ţĥé ŕéàļḿ šéţţîñĝš ţö àļļöŵ ñéŵ üšéŕš ţö çŕéàţé àççöüñţš. Çöñƒîĝüŕé ŠḾŢÞ îñ ţĥé ŕéàļḿ ƒöŕ éḿàîļ ṽéŕîƒîçàţîöñ.
Öţĥéŕ Þŕöṽîđéŕš
Ƒöŕ öţĥéŕ ÖÎĐÇ þŕöṽîđéŕš, çŕéàţé àñ ÖÀüţĥ2/ÖÎĐÇ àþþļîçàţîöñ ŵîţĥ:
- Ŕéđîŕéçţ ÜŔÎ:
https://your-domain.com/api/v1/auth/callback - Šçöþéš:
openid profile email - Ĝŕàñţ ţýþé: Àüţĥöŕîžàţîöñ çöđé ƒļöŵ
Šéţ BOWRAIN_OIDC_ISSUER_URL ţö ţĥé þŕöṽîđéŕ'š îššüéŕ ÜŔĻ (ƒöüñđ îñ ţĥé
.well-known/openid-configuration éñđþöîñţ).
Þŕöđüçţîöñ Ţîþš
ĴŴŢ Šéçŕéţ
Ĝéñéŕàţé à šţŕöñĝ ŕàñđöḿ šéçŕéţ ƒöŕ BOWRAIN_JWT_SECRET:
openssl rand -base64 32
Ñéṽéŕ üšé ţĥé đéƒàüļţ đéṽéļöþḿéñţ šéçŕéţ îñ þŕöđüçţîöñ.
Þéŕšîšţéñţ Šţöŕàĝé
Ţŵö ṽöļüḿéš ĥöļđ đüŕàƃļé šţàţé. Ƃàçķ ƃöţĥ ŵîţĥ ñàḿéđ ṽöļüḿéš öŕ ƃîñđ ḿöüñţš šö ţĥéý šüŕṽîṽé çöñţàîñéŕ ŕéšţàŕţš:
- ÞöšţĝŕéŠǪĻ: ţĥé àüţĥöŕîţàţîṽé šţöŕé, îñ
postgres-data(/var/lib/postgresql/data). - Ƃļöƃ šţöŕàĝé: îñ-ƒļîĝĥţ þüšĥ þàýļöàđš šĥàŕéđ ƃý ţĥé šéŕṽéŕ àñđ ŵöŕķéŕ,
îñ
blob-data(/data) ƒöŕ ţĥélocalƃàçķéñđ, öŕ àñ Š3 ƃüçķéţ.
volumes:
- /opt/bowrain/postgres:/var/lib/postgresql/data # bind mount
# or
- postgres-data:/var/lib/postgresql/data # named volume
Ŕéṽéŕšé Þŕöẋý
Ƒöŕ þŕöđüçţîöñ, þüţ ţĥé šţàçķ ƃéĥîñđ à ŕéṽéŕšé þŕöẋý (Ñĝîñẋ, Çàđđý, Ţŕàéƒîķ) ţö
ĥàñđļé ŢĻŠ ţéŕḿîñàţîöñ. Ţĥé ŕéƒéŕéñçé çöḿþöšé üšéš Ţŕàéƒîķ; ŵîţĥ àñöţĥéŕ þŕöẋý,
ŕöüţé /api àñđ ĝŔÞÇ (/neokapi.*) ţö bowrain-šéŕṽéŕ àñđ éṽéŕýţĥîñĝ éļšé ţö
bowrain-ŵéƃ. À ḿîñîḿàļ Ñĝîñẋ šéŕṽéŕ ƃļöçķ ƒŕöñţîñĝ Ţŕàéƒîķ (öŕ ţĥé šéŕṽîçéš):
server {
listen 443 ssl;
server_name bowrain.example.com;
ssl_certificate /etc/ssl/certs/bowrain.crt;
ssl_certificate_key /etc/ssl/private/bowrain.key;
location / {
proxy_pass http://localhost:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Ŵĥéñ üšîñĝ à ŕéṽéŕšé þŕöẋý, šéţ BOWRAIN_APP_PUBLIC_URL àñđ ţĥé ÖÎĐÇ çļîéñţ'š
ŕéđîŕéçţ ÜŔÎ ţö ţĥé þüƃļîç ĤŢŢÞŠ ÜŔĻ. Šéţ BOWRAIN_OIDC_PUBLIC_URL ţöö îƒ ţĥé
ƃŕöŵšéŕ ŕéàçĥéš ýöüŕ îđéñţîţý þŕöṽîđéŕ üñđéŕ à đéŕéñţ ñàḿé ţĥàñ ţĥé šéŕṽéŕ
đöéš.
BOWRAIN_FORCE_SECURE_COOKIES îš àļŕéàđý true ƃý đéƒàüļţ, ŵĥîçĥ îš ŵĥàţ ýöü
ŵàñţ ĥéŕé: ŢĻŠ ţéŕḿîñàţéš àţ ţĥé þŕöẋý, šö ŵîţĥöüţ îţ ţĥé Secure ƒļàĝ ŵöüļđ
đéþéñđ öñ ţĥé X-Forwarded-Proto ĥéàđéŕ àƃöṽé çöñţîñüîñĝ ţö àŕŕîṽé.
À šéŕṽéŕ îš þŕöđüçţîöñ üñļéšš BOWRAIN_ALLOW_INSECURE_DEV=1 šàýš öţĥéŕŵîšé, šö
à šéļƒ-ĥöšţéđ đéþļöýḿéñţ ĝéţš ţĥé šţŕîçţ öŕîĝîñ þöļîçý ƃý đéƒàüļţ. Ţĥàţ ƒļàĝ îš
ƒöŕ à ļöçàļ đéṽéļöþḿéñţ ƃöẋ àñđ šĥöüļđ ñéṽéŕ ƃé šéţ öñ àñýţĥîñĝ ŕéàçĥàƃļé ƒŕöḿ
ţĥé îñţéŕñéţ.
Đöçķéŕ Îḿàĝé Ţàĝš
À đéþļöýḿéñţ üšéš ţĥŕéé îḿàĝéš, bowrain-server, bowrain-worker, àñđ
bowrain-web, þüƃļîšĥéđ üñđéŕ ghcr.io/neokapi/:
| Ţàĝ | Đéšçŕîþţîöñ |
|---|---|
latest | Ḿöšţ ŕéçéñţ ŕéļéàšé |
X.Y.Z | Šþéçîƒîç ṽéŕšîöñ (ƒöŕ éẋàḿþļé 0.5.0) |
Þüļļ à šþéçîƒîç ṽéŕšîöñ (ķééþ šéŕṽéŕ, ŵöŕķéŕ, àñđ ŵéƃ öñ ţĥé šàḿé ţàĝ):
docker pull ghcr.io/neokapi/bowrain-server:0.5.0
docker pull ghcr.io/neokapi/bowrain-worker:0.5.0
docker pull ghcr.io/neokapi/bowrain-web:0.5.0
Ƃàçķüþ & Ŕéšţöŕé
Àļļ àüţĥöŕîţàţîṽé đàţà ļîṽéš îñ ÞöšţĝŕéŠǪĻ; ƃàçķ îţ üþ ŵîţĥ pg_dump. (Ţĥé ƃļöƃ
šţöŕé ĥöļđš öñļý îñ-ƒļîĝĥţ þüšĥ þàýļöàđš; çöḿḿîţţéđ çöñţéñţ îš îñ ÞöšţĝŕéŠǪĻ, šö
ţĥé ƃļöƃ šţöŕé đöéš ñöţ ñééđ ƃàçķîñĝ üþ.)
Ƃàçķüþ
docker compose -f deploy/docker/compose.yaml exec -T postgres \
pg_dump -U bowrain -Fc bowrain > bowrain-$(date +%Y%m%d).dump
Ŕéšţöŕé
docker compose -f deploy/docker/compose.yaml exec -T postgres \
pg_restore -U bowrain -d bowrain --clean --if-exists < bowrain-YYYYMMDD.dump
Šçĥéđüļéđ Ƃàçķüþš
Àđđ à çŕöñ ĵöƃ ƒöŕ ŕéĝüļàŕ ƃàçķüþš:
# Daily backup at 2 AM
0 2 * * * docker compose -f /opt/bowrain/deploy/docker/compose.yaml exec -T postgres pg_dump -U bowrain -Fc bowrain > /opt/backups/bowrain-$(date +\%Y\%m\%d).dump
ÇĻÎ Çöññéçţîöñ
Çöññéçţ kapi ţö ýöüŕ šéļƒ-ĥöšţéđ šéŕṽéŕ:
kapi auth login --server https://bowrain.example.com
Ţĥîš šţàŕţš à đéṽîçé àüţĥöŕîžàţîöñ ƒļöŵ. Öþéñ ţĥé ÜŔĻ šĥöŵñ îñ ýöüŕ ţéŕḿîñàļ, àüţĥéñţîçàţé ŵîţĥ ýöüŕ îđéñţîţý þŕöṽîđéŕ, àñđ ţĥé ÇĻÎ ŕéçéîṽéš à ţöķéñ àüţöḿàţîçàļļý.