Production-ready Kubernetes deployment manifests for the OCTO platform — Kustomize bases, environment overlays, and secret templates for all services.
52
stars
91
commits
Shell
primary language
Aug 26, 2026
updated
The official OOTB ("out of the box") deployment for OCTO — both the
single-node Docker Compose stack under docker/ and the
multi-node Kubernetes manifests under kustomize/ for
the OCTO platform.
This repository is the single source of truth for OCTO deployment. The
deployment artefacts that previously lived inside Mininglamp-OSS/octo-server
(docker/octo/, docker/tsdd/) are now retired; consume them from
here instead.
OCTO is an open-source team collaboration and communication platform designed for lawful internal organizational use. It is provided as a technology framework — the OCTO project and its contributors do not operate, host, or manage any messaging service for end users.
You must not use OCTO, directly or indirectly, for any of the following:
By deploying OCTO, you (the deployer/operator) assume full responsibility for:
OCTO is provided "AS IS" without warranty of any kind, express or implied. The OCTO project, Mininglamp, and its contributors shall not be held liable for any claim, damage, legal consequence, regulatory penalty, or other liability arising from the deployment, operation, or use of this software. This includes, without limitation, any liability arising from a deployer's failure to comply with applicable laws and regulations.
See LICENSE for the full Apache 2.0 license terms.
中文版:README.zh.md
For a single-node Docker Compose trial, use
docker/in this repository — it brings up the full OCTO stack (server + admin + web + matter + smart-summary + WuKongIM + MySQL + Redis + MinIO + nginx) with onedocker compose up -d. Seedocker/README.mdfor the walkthrough (中文版docker/README.zh.md). Thiskustomize/tree remains the canonical reference for multi-node Kubernetes deployment.
git clone https://github.com/Mininglamp-OSS/octo-deployment.git
cd octo-deployment
./setup.sh # step 1: interactive — auto-detects public IP, generates all secrets in docker/.env (no sudo)
sudo ./setup.sh --up # step 2: start the stack (start-only — never regenerates secrets); sudo needed for Docker + .env
sudo ./setup.sh --smoke-test # step 3: admin login + presign PUT end-to-end check (alias: --verify, deprecated)
--up is a start-only subcommand (R6 / GH#33, R8 / GH#43): it
requires an existing docker/.env (generated by step 1). If
docker/.env is missing, --up exits 1 with a concrete remediation
message — it will not silently regenerate secrets, because a single
typo in deploy automation would otherwise rotate every
MySQL/MinIO/admin secret on a live host. To bootstrap + start in one
command (generating fresh secrets), pass --up --force explicitly:
sudo ./setup.sh --non-interactive --ip <PUBLIC_IP> --up --force # explicit one-shot bootstrap (writes new secrets)
--up runs docker compose up -d --wait --wait-timeout 240 and
blocks until every long-running service reports (healthy) and every
one-shot init job (preflight, minio-init) exits 0. On timeout or
startup failure it prints compose ps, the specific failing service
names, and a logs <svc> hint for each, then exits 1. The wrapper
retries once on a soft timeout (warm mysql / image caches make the
second attempt typically <10s), so worst-case wall-clock is 2 × 240s.
It prints a . every 5 seconds while waiting so you can see the run
is alive. --up (without --force) will never rewrite/regenerate
secrets in docker/.env — that file is owned by step 1's caller, and
--up only chown root:root + chmod 600 it (ownership hardening,
never a content change).
For unattended provisioning, do step 1 non-interactively and chain into step 2:
./setup.sh --non-interactive --ip <PUBLIC_IP> # step 1: gen .env, no prompts
sudo ./setup.sh --up # step 2: start + wait-for-healthy
sudo ./setup.sh --smoke-test # step 3: verify
setup.sh prints the admin URL + superAdmin password at the end of
step 1. The password is also persisted to docker/.env (mode 600) —
treat that file as a secret and rotate the password from the admin
UI after first login (see docker/README.md "First-admin
bootstrap"). After step 2 the file ends up owned by root (because
--up runs under sudo); both --up and --smoke-test continue to
require sudo because the file contains MySQL/MinIO/admin credentials
and Compose control inputs (COMPOSE_PROJECT_NAME,
OCTO_MASTER_KEY, OCTO_ADMIN_PWD, …) — user-write would silently
alter the next privileged docker compose run.
The OOTB stack is
single-port for clients: only TCP 28080 (OCTO_HTTP_PORT, the
nginx HTTP vhost) needs to be open. With HTTPS the client port becomes
28443 (OCTO_HTTPS_PORT). All other ports (MinIO, MySQL, Redis,
WuKongIM monitor, direct REST) default to loopback.
Uninstall / reset is interactive:
./setup.sh --uninstall
# Three granularity levels: 1) full 2) data-only 3) containers only
Full docs: docker/README.md (Uninstall / Reset,
Network surface, MinIO bootstrap, Hardening checklist, troubleshooting).
| Service | Image | Container ports |
|---|---|---|
| octo-server | mininglamposs/octo-server | 8090 (http) / 6979 (grpc) |
| octo-web | mininglamposs/octo-web | 80 |
| octo-admin | mininglamposs/octo-admin | 80 |
| octo-matter | mininglamposs/octo-matter | 8080 |
| octo-smart-summary-api | mininglamposs/octo-smart-summary-api | 8080 / 8081 |
| octo-smart-summary-worker | mininglamposs/octo-smart-summary-worker | 8082 |
External infrastructure expected (provisioned separately, not in this repo):
octo (IM core), octo_matter, octo_summaryOCTO does not embed an IM engine — it consumes WuKongIM over the latter's HTTP API and webhook gRPC. You can run any of the deployment modes documented at https://docs.githubim.com/installation/overview:
Whichever you pick, three things must line up between WuKongIM and octo-server:
| WuKongIM config | OCTO setting |
|---|---|
managerToken | octo-server-config.tsdd.yaml → wukongIM.managerToken (also set as WUKONGIM_MANAGER_TOKEN in octo-server-secret for env-driven setups) |
webhook.grpcAddr (the address WuKongIM dials back into) | <octo-server-svc>:6979 so message events reach OCTO |
external.ip / external.wsAddr / external.wssAddr (the public endpoints WuKongIM advertises to clients) | should match how end-user clients reach WuKongIM via your ingress / LB |
Message search (Kafka + OpenSearch[analysis-ik] + es-indexer) is an optional component and is default OFF on every entry point. Each entry point opts in explicitly; the default install path renders zero search resources.
| Entry point | Opt-in | Default |
|---|---|---|
| Docker Compose | ./setup.sh --search (or COMPOSE_PROFILES=search) | off |
| Helm | --set search.enabled=true | off |
| Kustomize | kubectl apply -k kustomize/search (standalone, not referenced by base/overlays) | off |
All three deploy the search infrastructure only; wiring octo-server onto
OpenSearch is a separate, owner-gated step. See
docker/README.md "Search profile",
helm/octo/README.md "Search (optional)", and
kustomize/search/README.md.
kustomize/
├── base/ Generic OSS templates (this is the canonical reference)
│ ├── kustomization.yaml Pulls all resources, applies image transformer
│ ├── octo-*.yaml Deployments + Services
│ ├── octo-*-config.yaml ConfigMaps (non-sensitive)
│ └── octo-*-secret.example.yaml
│ Secret templates with CHANGE_ME_* placeholders
└── overlays/
├── dev/ Image tag = "dev"
└── prod/ Multi-replica production overlay
For single-node Docker Compose evaluation, go to
docker/README.md— it owns the prerequisites checklist (Docker daemon, ports, RAM/disk, image-pull network access), thesetup.shone-liner, and the pre-flight warning for hosts that already run another OCTO stack.The walkthrough below is for the Kubernetes / kustomize path.
kubectl apply against (≥ 1 worker
node; production overlay assumes a multi-node cluster).kubectl ≥ 1.27 on your shell with kubeconfig pointing at the
target cluster.octo, octo_matter, octo_summary), Redis 7, WuKongIM ≥ v2,
and an S3-compatible object store. The base manifests reference
these via Secrets / ConfigMaps and assume you bring them yourself.Namespace is not hardcoded — specify it on the CLI.
# 1. Create the target namespace
kubectl create namespace octo
# 2. Prepare Secrets (one-time per environment).
# Copy the *.example templates, fill in real values, then apply.
cd kustomize/base
for f in *-secret.example.yaml; do cp "$f" "${f/.example/}"; done
$EDITOR octo-*-secret.yaml # replace every CHANGE_ME_*
kubectl apply -n octo \
-f octo-server-secret.yaml \
-f octo-matter-secret.yaml \
-f octo-smart-summary-secret.yaml
# 3. Apply ConfigMaps + workloads
kubectl apply -n octo -k .
For environment-specific overrides:
kubectl apply -n octo-dev -k kustomize/overlays/dev
kubectl apply -n octo-prod -k kustomize/overlays/prod
Preview the rendered manifests without applying:
kubectl kustomize kustomize/base
Edit kustomize/base/kustomization.yaml and replace newTag: latest with a release tag, e.g. newTag: v0.1.0. Each images: entry can be overridden independently.
Each service consumes a small Secret. Required keys per service:
| Secret | Required keys |
|---|---|
octo-server-secret | DM_MYSQL_DSN, DM_REDIS_ADDR, WUKONGIM_MANAGER_TOKEN, OCTO_ADMIN_PASSWORD, OCTO_MASTER_KEY, DMWORK_MASTER_KEY (legacy alias of master key), NOTIFY_INTERNAL_TOKEN, OCTO_INTERNAL_HMAC_SECRET, OCTO_JWT_SECRET. Plus OIDC / COS / SMTP / APNS keys when those features are enabled. |
octo-matter-secret | MYSQL_DSN, LLM_API_KEY, NOTIFY_INTERNAL_TOKEN (must match octo-server-secret). |
octo-smart-summary-secret | MYSQL_DSN, IM_MYSQL_DSN, LLM_API_URL, LLM_API_KEY. |
Generate strong random tokens with:
openssl rand -hex 32 # for *_TOKEN / *_SECRET / MASTER_KEY
openssl rand -base64 32 # for DM_OIDC_RT_ENC_KEY
Secret files (
*-secret.yaml) are git-ignored. Only the*.example.yamltemplates are tracked.
Default image references point at docker.io/mininglamposs/<service>:latest. To use a self-hosted registry, edit the images: block in kustomize/base/kustomization.yaml:
images:
- name: mininglamposs/octo-server
newName: my-registry.example.com/octo/octo-server
newTag: v0.1.0
For private registries that require authentication, create a Docker config Secret and reference it via imagePullSecrets on each Deployment (or patch via overlay).
octo-web + octo-admin (current README assumes you bring your own controller).p8 key mounting (or instructions to disable iOS push)Apache 2.0 — same as the rest of the OCTO suite.
Shell
91.8%
Go Template
7.7%
Production-ready Kubernetes deployment manifests for the OCTO platform — Kustomize bases, environment overlays, and secret templates for all services.
52
stars
91
commits
Shell
primary language
Aug 26, 2026
updated
The official OOTB ("out of the box") deployment for OCTO — both the
single-node Docker Compose stack under docker/ and the
multi-node Kubernetes manifests under kustomize/ for
the OCTO platform.
This repository is the single source of truth for OCTO deployment. The
deployment artefacts that previously lived inside Mininglamp-OSS/octo-server
(docker/octo/, docker/tsdd/) are now retired; consume them from
here instead.
OCTO is an open-source team collaboration and communication platform designed for lawful internal organizational use. It is provided as a technology framework — the OCTO project and its contributors do not operate, host, or manage any messaging service for end users.
You must not use OCTO, directly or indirectly, for any of the following:
By deploying OCTO, you (the deployer/operator) assume full responsibility for:
OCTO is provided "AS IS" without warranty of any kind, express or implied. The OCTO project, Mininglamp, and its contributors shall not be held liable for any claim, damage, legal consequence, regulatory penalty, or other liability arising from the deployment, operation, or use of this software. This includes, without limitation, any liability arising from a deployer's failure to comply with applicable laws and regulations.
See LICENSE for the full Apache 2.0 license terms.
中文版:README.zh.md
For a single-node Docker Compose trial, use
docker/in this repository — it brings up the full OCTO stack (server + admin + web + matter + smart-summary + WuKongIM + MySQL + Redis + MinIO + nginx) with onedocker compose up -d. Seedocker/README.mdfor the walkthrough (中文版docker/README.zh.md). Thiskustomize/tree remains the canonical reference for multi-node Kubernetes deployment.
git clone https://github.com/Mininglamp-OSS/octo-deployment.git
cd octo-deployment
./setup.sh # step 1: interactive — auto-detects public IP, generates all secrets in docker/.env (no sudo)
sudo ./setup.sh --up # step 2: start the stack (start-only — never regenerates secrets); sudo needed for Docker + .env
sudo ./setup.sh --smoke-test # step 3: admin login + presign PUT end-to-end check (alias: --verify, deprecated)
--up is a start-only subcommand (R6 / GH#33, R8 / GH#43): it
requires an existing docker/.env (generated by step 1). If
docker/.env is missing, --up exits 1 with a concrete remediation
message — it will not silently regenerate secrets, because a single
typo in deploy automation would otherwise rotate every
MySQL/MinIO/admin secret on a live host. To bootstrap + start in one
command (generating fresh secrets), pass --up --force explicitly:
sudo ./setup.sh --non-interactive --ip <PUBLIC_IP> --up --force # explicit one-shot bootstrap (writes new secrets)
--up runs docker compose up -d --wait --wait-timeout 240 and
blocks until every long-running service reports (healthy) and every
one-shot init job (preflight, minio-init) exits 0. On timeout or
startup failure it prints compose ps, the specific failing service
names, and a logs <svc> hint for each, then exits 1. The wrapper
retries once on a soft timeout (warm mysql / image caches make the
second attempt typically <10s), so worst-case wall-clock is 2 × 240s.
It prints a . every 5 seconds while waiting so you can see the run
is alive. --up (without --force) will never rewrite/regenerate
secrets in docker/.env — that file is owned by step 1's caller, and
--up only chown root:root + chmod 600 it (ownership hardening,
never a content change).
For unattended provisioning, do step 1 non-interactively and chain into step 2:
./setup.sh --non-interactive --ip <PUBLIC_IP> # step 1: gen .env, no prompts
sudo ./setup.sh --up # step 2: start + wait-for-healthy
sudo ./setup.sh --smoke-test # step 3: verify
setup.sh prints the admin URL + superAdmin password at the end of
step 1. The password is also persisted to docker/.env (mode 600) —
treat that file as a secret and rotate the password from the admin
UI after first login (see docker/README.md "First-admin
bootstrap"). After step 2 the file ends up owned by root (because
--up runs under sudo); both --up and --smoke-test continue to
require sudo because the file contains MySQL/MinIO/admin credentials
and Compose control inputs (COMPOSE_PROJECT_NAME,
OCTO_MASTER_KEY, OCTO_ADMIN_PWD, …) — user-write would silently
alter the next privileged docker compose run.
The OOTB stack is
single-port for clients: only TCP 28080 (OCTO_HTTP_PORT, the
nginx HTTP vhost) needs to be open. With HTTPS the client port becomes
28443 (OCTO_HTTPS_PORT). All other ports (MinIO, MySQL, Redis,
WuKongIM monitor, direct REST) default to loopback.
Uninstall / reset is interactive:
./setup.sh --uninstall
# Three granularity levels: 1) full 2) data-only 3) containers only
Full docs: docker/README.md (Uninstall / Reset,
Network surface, MinIO bootstrap, Hardening checklist, troubleshooting).
| Service | Image | Container ports |
|---|---|---|
| octo-server | mininglamposs/octo-server | 8090 (http) / 6979 (grpc) |
| octo-web | mininglamposs/octo-web | 80 |
| octo-admin | mininglamposs/octo-admin | 80 |
| octo-matter | mininglamposs/octo-matter | 8080 |
| octo-smart-summary-api | mininglamposs/octo-smart-summary-api | 8080 / 8081 |
| octo-smart-summary-worker | mininglamposs/octo-smart-summary-worker | 8082 |
External infrastructure expected (provisioned separately, not in this repo):
octo (IM core), octo_matter, octo_summaryOCTO does not embed an IM engine — it consumes WuKongIM over the latter's HTTP API and webhook gRPC. You can run any of the deployment modes documented at https://docs.githubim.com/installation/overview:
Whichever you pick, three things must line up between WuKongIM and octo-server:
| WuKongIM config | OCTO setting |
|---|---|
managerToken | octo-server-config.tsdd.yaml → wukongIM.managerToken (also set as WUKONGIM_MANAGER_TOKEN in octo-server-secret for env-driven setups) |
webhook.grpcAddr (the address WuKongIM dials back into) | <octo-server-svc>:6979 so message events reach OCTO |
external.ip / external.wsAddr / external.wssAddr (the public endpoints WuKongIM advertises to clients) | should match how end-user clients reach WuKongIM via your ingress / LB |
Message search (Kafka + OpenSearch[analysis-ik] + es-indexer) is an optional component and is default OFF on every entry point. Each entry point opts in explicitly; the default install path renders zero search resources.
| Entry point | Opt-in | Default |
|---|---|---|
| Docker Compose | ./setup.sh --search (or COMPOSE_PROFILES=search) | off |
| Helm | --set search.enabled=true | off |
| Kustomize | kubectl apply -k kustomize/search (standalone, not referenced by base/overlays) | off |
All three deploy the search infrastructure only; wiring octo-server onto
OpenSearch is a separate, owner-gated step. See
docker/README.md "Search profile",
helm/octo/README.md "Search (optional)", and
kustomize/search/README.md.
kustomize/
├── base/ Generic OSS templates (this is the canonical reference)
│ ├── kustomization.yaml Pulls all resources, applies image transformer
│ ├── octo-*.yaml Deployments + Services
│ ├── octo-*-config.yaml ConfigMaps (non-sensitive)
│ └── octo-*-secret.example.yaml
│ Secret templates with CHANGE_ME_* placeholders
└── overlays/
├── dev/ Image tag = "dev"
└── prod/ Multi-replica production overlay
For single-node Docker Compose evaluation, go to
docker/README.md— it owns the prerequisites checklist (Docker daemon, ports, RAM/disk, image-pull network access), thesetup.shone-liner, and the pre-flight warning for hosts that already run another OCTO stack.The walkthrough below is for the Kubernetes / kustomize path.
kubectl apply against (≥ 1 worker
node; production overlay assumes a multi-node cluster).kubectl ≥ 1.27 on your shell with kubeconfig pointing at the
target cluster.octo, octo_matter, octo_summary), Redis 7, WuKongIM ≥ v2,
and an S3-compatible object store. The base manifests reference
these via Secrets / ConfigMaps and assume you bring them yourself.Namespace is not hardcoded — specify it on the CLI.
# 1. Create the target namespace
kubectl create namespace octo
# 2. Prepare Secrets (one-time per environment).
# Copy the *.example templates, fill in real values, then apply.
cd kustomize/base
for f in *-secret.example.yaml; do cp "$f" "${f/.example/}"; done
$EDITOR octo-*-secret.yaml # replace every CHANGE_ME_*
kubectl apply -n octo \
-f octo-server-secret.yaml \
-f octo-matter-secret.yaml \
-f octo-smart-summary-secret.yaml
# 3. Apply ConfigMaps + workloads
kubectl apply -n octo -k .
For environment-specific overrides:
kubectl apply -n octo-dev -k kustomize/overlays/dev
kubectl apply -n octo-prod -k kustomize/overlays/prod
Preview the rendered manifests without applying:
kubectl kustomize kustomize/base
Edit kustomize/base/kustomization.yaml and replace newTag: latest with a release tag, e.g. newTag: v0.1.0. Each images: entry can be overridden independently.
Each service consumes a small Secret. Required keys per service:
| Secret | Required keys |
|---|---|
octo-server-secret | DM_MYSQL_DSN, DM_REDIS_ADDR, WUKONGIM_MANAGER_TOKEN, OCTO_ADMIN_PASSWORD, OCTO_MASTER_KEY, DMWORK_MASTER_KEY (legacy alias of master key), NOTIFY_INTERNAL_TOKEN, OCTO_INTERNAL_HMAC_SECRET, OCTO_JWT_SECRET. Plus OIDC / COS / SMTP / APNS keys when those features are enabled. |
octo-matter-secret | MYSQL_DSN, LLM_API_KEY, NOTIFY_INTERNAL_TOKEN (must match octo-server-secret). |
octo-smart-summary-secret | MYSQL_DSN, IM_MYSQL_DSN, LLM_API_URL, LLM_API_KEY. |
Generate strong random tokens with:
openssl rand -hex 32 # for *_TOKEN / *_SECRET / MASTER_KEY
openssl rand -base64 32 # for DM_OIDC_RT_ENC_KEY
Secret files (
*-secret.yaml) are git-ignored. Only the*.example.yamltemplates are tracked.
Default image references point at docker.io/mininglamposs/<service>:latest. To use a self-hosted registry, edit the images: block in kustomize/base/kustomization.yaml:
images:
- name: mininglamposs/octo-server
newName: my-registry.example.com/octo/octo-server
newTag: v0.1.0
For private registries that require authentication, create a Docker config Secret and reference it via imagePullSecrets on each Deployment (or patch via overlay).
octo-web + octo-admin (current README assumes you bring your own controller).p8 key mounting (or instructions to disable iOS push)Apache 2.0 — same as the rest of the OCTO suite.
Shell
91.8%
Go Template
7.7%