Šķîþ ţö ḿàîñ çöñţéñţ

Šéļƒ-Ĥöšţîñĝ

Ŕüñ ýöüŕ öŵñ 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_COOKIEStrueḾàŕķš šéššîöñ çööķîéš Secure ŕéĝàŕđļéšš öƒ ţĥé ŕéǫüéšţ šçĥéḿé
BOWRAIN_OIDC_CLIENT_IDbowrainÖÎĐÇ çļîéñţ ÎĐ
BOWRAIN_OIDC_CLIENT_SECRETÖÎĐÇ çļîéñţ šéçŕéţ
BOWRAIN_QUEUE_BACKENDsqs šéļéçţš ţĥé ŠǪŠ ĵöƃ-ǫüéüé ƃàçķéñđ
SQS_ENDPOINTŠǪŠ éñđþöîñţ öṽéŕŕîđé ƒöŕ ÉļàšţîçḾǪ/ĻöçàļŠţàçķ; éḿþţý öñ ÀŴŠ
BOWRAIN_EVENT_BACKENDredis ŕüñš ţĥé éṽéñţ ƃüš öñ Ŕéđîš Šţŕéàḿš
BOWRAIN_REDIS_URLŔéđîš ÜŔĻ (éṽéñţ ƃüš, çàçĥîñĝ, šéššîöñ šţàţé)
BLOB_STORAGE_BACKENDlocallocal öŕ s3 ƒöŕ îñ-ƒļîĝĥţ þüšĥ þàýļöàđš
BLOB_STORAGE_LOCAL_DIRĻöçàļ ƃļöƃ đîŕéçţöŕý (šĥàŕéđ ŵîţĥ ţĥé ŵöŕķéŕ)
S3_BLOB_BUCKETƂüçķéţ ƒöŕ ţĥé s3 ƃàçķéñđ (šéţţîñĝ îţ šéļéçţš s3)
BOWRAIN_SMTP_HOSTŠḾŢÞ šéŕṽéŕ host:port ƒöŕ ţŕàñšàçţîöñàļ éḿàîļš
BOWRAIN_SMTP_FROMŠéñđéŕ éḿàîļ àđđŕéšš ƒöŕ ţŕàñšàçţîöñàļ éḿàîļš
BOWRAIN_PORT8080ĤŢŢÞ þöŕţ ţö ļîšţéñ öñ
BOWRAIN_HOST0.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

Ţĥîš šţàŕţš à đéṽîçé àüţĥöŕîžàţîöñ ƒļöŵ. Öþéñ ţĥé ÜŔĻ šĥöŵñ îñ ýöüŕ ţéŕḿîñàļ, àüţĥéñţîçàţé ŵîţĥ ýöüŕ îđéñţîţý þŕöṽîđéŕ, àñđ ţĥé ÇĻÎ ŕéçéîṽéš à ţöķéñ àüţöḿàţîçàļļý.