# π Documize Community β Docker Deployment
**Self-hosted knowledge management Β· v5.14.0 Β· MySQL 8 Β· Docker Compose**
[](https://github.com/documize/community)
[](https://hub.docker.com/_/mysql)
[](https://docs.docker.com/compose/)
[](https://www.gnu.org/licenses/agpl-3.0.en.html)
A production-ready Docker Compose stack for [Documize Community](https://github.com/documize/community) β an open-source, self-hosted alternative to Confluence, built with Go + EmberJS.
[Quick Start](#-quick-start) Β· [Configuration](#-configuration) Β· [Architecture](#-architecture) Β· [Operations](#-day-to-day-operations) Β· [Troubleshooting](#-troubleshooting)
---
## β¨ Features
- **Single binary deployment** β Documize ships as one statically-linked Go binary; no runtime dependencies beyond a database
- **Zero reboot-loop risk** β Init-container pattern separates the one-time binary download from the always-running app container
- **Full-text search** β MySQL configured with `ft-min-word-len=3` and `utf8mb4` collation as required by Documize
- **Secret-free Compose file** β All credentials live in `.env`; `docker-compose.yml` contains no plaintext passwords
- **Named volume persistence** β Both database data and the app binary survive container restarts and upgrades
- **SMTP support** β Optional email notifications configured entirely via environment variables
---
## π Prerequisites
| Requirement | Minimum version |
|---|---|
| Docker Engine | 24.0+ |
| Docker Compose | v2.20+ (included with Docker Desktop) |
| Available port | TCP `5001` (configurable) |
| RAM | 512 MB free (1 GB recommended) |
| Disk | 2 GB free |
| Internet | Required on first start to download the Documize binary (~25 MB) |
---
## π Quick Start
```bash
# 1. Clone or download this repository
git clone https://github.com/your-org/documize-docker.git
cd documize-docker
# 2. Create your environment file from the template
cp .env.template .env
# 3. Generate and set your secrets
echo "MYSQL_PASSWORD=$(openssl rand -base64 24)"
echo "MYSQL_ROOT_PASSWORD=$(openssl rand -base64 24)"
echo "DOCUMIZE_SALT=$(openssl rand -hex 32)"
# Paste each value into .env
# 4. Protect the file and add to .gitignore
chmod 600 .env
echo ".env" >> .gitignore
# 5. Start the stack
docker compose up -d
# 6. Watch the logs until Documize is ready (~30β60 s)
docker compose logs -f
# 7. Open the setup wizard
open http://localhost:5001
```
> **Activation key** β The Community edition requires a free activation key. Register your email at [documize.com/community/get-started](https://www.documize.com/community/get-started) to receive one instantly.
---
## π Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Host β
β β
β ββββββββββββββββ exits 0 βββββββββββββββββββββββββββ β
β β documize-initβ βββββββββββΊ β app_bin volume β β
β β (alpine:3.19)β downloads β /app/bin/documize β β
β β restart: no β binary once ββββββββββββ¬βββββββββββββββ β
β ββββββββββββββββ β mounts β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β documize-app (alpine:3.19) β β
β β restart: unless-stopped β β
β β exec /app/bin/documize ββββββΌββ :5001
β ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββ β
β β TCP 3306 (internal only) β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β documize-db (mysql:8) β β
β β restart: unless-stopped β β
β β healthcheck: mysqladmin ping β β
β ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββ β
β β β
β ββββββββΌβββββββ β
β β db_data β β
β β volume β β
β βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Startup Sequence
1. `documize-init` starts β installs `curl` β downloads binary to `app_bin` volume β **exits 0**
2. `documize-db` starts β MySQL initialises β healthcheck passes β
3. `documize-app` starts (only after both conditions above are met) β exec's binary β serves on `:5001`
### Why the Init-Container Pattern?
Downloading a binary inside the main container's command creates a reboot loop: any failure causes Docker to restart the container, which retriggers the download. Separating the download into a `restart: "no"` init container means the main app container only ever does one thing β run the binary β with no network calls or failure modes on restart.
---
## βοΈ Configuration
### File Layout
```
documize-docker/
βββ docker-compose.yml # Stack definition β references ${VARS} from .env
βββ .env.template # Template β copy to .env and fill in secrets
βββ .env # Your secrets β NEVER commit this file
βββ README.md # This file
```
### Step 1 β Set up your `.env` file
Copy the template and fill in all values marked β οΈ:
```bash
cp .env.template .env
```
### Step 2 β Environment Variable Reference
#### ποΈ MySQL Database
| Variable | Default | Required | Description |
|---|---|---|---|
| `MYSQL_DATABASE` | `documize` | Pre-filled | Database name created on first start |
| `MYSQL_USER` | `documize` | Pre-filled | MySQL user Documize connects as |
| `MYSQL_PASSWORD` | β | β οΈ **Change** | Password for the `documize` MySQL user. Must match the DSN in `DOCUMIZEDB`. Generate: `openssl rand -base64 24` |
| `MYSQL_ROOT_PASSWORD` | β | β οΈ **Change** | MySQL root password for admin access. Not used by Documize. Generate: `openssl rand -base64 24` |
#### π Documize Application
| Variable | Default | Required | Description |
|---|---|---|---|
| `DOCUMIZE_PORT` | `5001` | Pre-filled | Host port Documize is exposed on. Change the left side of the `ports` mapping. |
| `DOCUMIZE_SALT` | β | β οΈ **Change** | Password hashing salt. Must be β₯ 32 random characters. Generate: `openssl rand -hex 32`. **Set once β never change after first run.** |
#### π§ SMTP Email (Optional)
All five SMTP variables must be set to enable email. Leave `SMTP_HOST` blank to disable.
| Variable | Default | Description |
|---|---|---|
| `SMTP_HOST` | _(blank)_ | SMTP server hostname (e.g. `smtp.gmail.com`) |
| `SMTP_PORT` | `587` | SMTP port β `587` for STARTTLS, `465` for SSL/TLS |
| `SMTP_USER` | _(blank)_ | SMTP authentication username |
| `SMTP_PASSWORD` | _(blank)_ | SMTP authentication password or app-specific password |
| `SMTP_SENDER` | `documize@example.com` | From address on outgoing emails |
---
### MySQL Startup Flags
These flags are passed to MySQL 8 via the `command` key in `docker-compose.yml` and are **required** for Documize to function correctly. Do not remove them.
| Flag | Value | Purpose |
|---|---|---|
| `--character-set-server` | `utf8mb4` | Full Unicode support including emoji |
| `--collation-server` | `utf8mb4_unicode_ci` | Case-insensitive Unicode collation |
| `--ft-min-word-len` | `3` | Minimum word length for full-text search index β Documize requires exactly `3` |
| `--innodb-file-per-table` | `1` | Each table in its own `.ibd` file β improves storage reclaim |
| `--max-allowed-packet` | `256M` | Maximum packet size for large document imports |
---
### Changing the Host Port
Edit the `ports` mapping in `docker-compose.yml` **and** the `DOCUMIZE_PORT` value in `.env`:
```yaml
# docker-compose.yml
ports:
- "${DOCUMIZE_PORT}:5001" # host:container
```
```bash
# .env
DOCUMIZE_PORT=8080
```
---
### Named Volumes
| Volume | Mount path | Purpose |
|---|---|---|
| `db_data` | `/var/lib/mysql` | All MySQL data β content, users, settings. Never delete unless wiping everything. |
| `app_bin` | `/app/bin` | The Documize binary. Safe to delete to force a re-download on next start. |
---
## π Security
### Checklist
- [ ] `MYSQL_PASSWORD` changed from placeholder
- [ ] `MYSQL_ROOT_PASSWORD` changed from placeholder
- [ ] `DOCUMIZE_SALT` generated with `openssl rand -hex 32`
- [ ] `.env` added to `.gitignore`
- [ ] `.env` permissions set to `600` (`chmod 600 .env`)
- [ ] MySQL `ports` mapping removed from `docker-compose.yml` (production only)
- [ ] Documize placed behind a reverse proxy with TLS (production only)
### Remove the Database Port Mapping (Production)
The `db` service does not expose a port by default β MySQL is only reachable within the `documize_net` Docker network. If you added a port for local debugging, remove it before deploying:
```yaml
# db service β remove or comment out for production:
# ports:
# - "3306:3306"
```
### Reverse Proxy with TLS
Documize serves plain HTTP. In production, terminate TLS at a reverse proxy. Example **Caddy** config:
```
docs.example.com {
reverse_proxy localhost:5001
}
```
Example **Nginx** config:
```nginx
server {
listen 443 ssl;
server_name docs.example.com;
ssl_certificate /etc/ssl/certs/docs.crt;
ssl_certificate_key /etc/ssl/private/docs.key;
location / {
proxy_pass http://localhost:5001;
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;
}
}
```
---
## π
Day-to-Day Operations
### Start / Stop / Restart
```bash
docker compose up -d # start all services (detached)
docker compose stop # graceful stop β data preserved
docker compose start # resume after stop
docker compose restart # restart all services
docker compose down # stop and remove containers (volumes kept)
docker compose down -v # β οΈ DESTRUCTIVE β removes containers AND volumes
```
### View Logs
```bash
docker compose logs -f # all services, follow
docker compose logs -f app # Documize app only
docker compose logs -f db # MySQL only
docker compose logs --tail=100 app # last 100 lines
```
### Check Status
```bash
docker compose ps
```
Expected healthy state:
```
NAME IMAGE STATUS
documize-init alpine:3.19 Exited (0) β correct: one-shot
documize-db mysql:8 healthy
documize-app alpine:3.19 running
```
### Open a MySQL Shell
```bash
docker exec -it documize-db mysql -u documize -p documize
# enter MYSQL_PASSWORD when prompted
```
---
## πΎ Backup & Restore
### Backup the Database
```bash
docker exec documize-db \
mysqldump -u documize -p"${MYSQL_PASSWORD}" documize \
> documize-backup-$(date +%Y%m%d-%H%M%S).sql
```
### Restore the Database
```bash
docker exec -i documize-db \
mysql -u documize -p"${MYSQL_PASSWORD}" documize \
< documize-backup-20240101-120000.sql
```
### Backup the Raw Volume (optional)
```bash
docker run --rm \
-v documize_db_data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/db_data-$(date +%Y%m%d).tar.gz -C /data .
```
---
## β¬οΈ Upgrading Documize
> β οΈ **Always back up the database before upgrading.**
```bash
# 1. Back up
docker exec documize-db mysqldump -u documize -p"${MYSQL_PASSWORD}" documize > pre-upgrade-backup.sql
# 2. Stop the stack
docker compose down
# 3. Remove the cached binary to force re-download of the new version
docker volume rm documize_app_bin
# 4. Update the download URL in docker-compose.yml (app-init command) to the new version
# 5. Start and watch for successful migration messages
docker compose up -d
docker compose logs -f app
```
Documize runs database schema migrations automatically on startup.
---
## π Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
| `app-init` exits with code `127` | `curl` not found β `apk` failed | Check internet connectivity and retry: `docker compose down -v && docker compose up -d` |
| `app-init` exits with code `22` or `28` | Binary download failed | Check outbound HTTPS access to `community-downloads.s3.us-east-2.amazonaws.com` |
| `documize-app` keeps restarting | MySQL not healthy or DSN mismatch | Run `docker compose logs db`. Verify `MYSQL_PASSWORD` in `.env` matches the password in `DOCUMIZEDB` |
| Setup wizard shows DB connection error | DSN credentials mismatch | Ensure `MYSQL_PASSWORD` in `.env` is identical to the password in the `DOCUMIZEDB` connection string |
| Port `5001` already in use | Port conflict on host | Change `DOCUMIZE_PORT` in `.env` and restart |
| `app-init` exits with code `0` but binary won't run | Wrong CPU architecture | The default binary is `linux-amd64`. On ARM (e.g. Raspberry Pi, Apple Silicon Linux), replace the download URL with the `linux-arm64` binary |
| Full-text search returns no results | MySQL FTS config missing | Confirm `--ft-min-word-len=3` is present in the `db` `command` block |
| Lost `DOCUMIZE_SALT` β users locked out | Salt cannot be recovered | Restore from a database backup taken before the salt was changed |
| Docker Compose variable not substituted | `.env` file missing or wrong path | Ensure `.env` is in the **same directory** as `docker-compose.yml` |
---
## π File Reference
```
.
βββ docker-compose.yml # Stack definition β edit to change ports and resource limits
βββ .env.template # Commit this β safe template with no real secrets
βββ .env # Do NOT commit β your actual secrets
βββ README.md # This file
```
| Docker resource | Type | Purpose |
|---|---|---|
| `documize-db` | Container | MySQL 8 database |
| `documize-init` | Container | One-shot binary downloader |
| `documize-app` | Container | Documize application |
| `documize_net` | Network | Private bridge β only `app` can reach `db` |
| `db_data` | Volume | MySQL data directory |
| `app_bin` | Volume | Documize binary cache |
---
## π Quick-Reference Commands
```bash
# ββ Setup ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
cp .env.template .env && chmod 600 .env # create secrets file
openssl rand -hex 32 # generate DOCUMIZE_SALT
openssl rand -base64 24 # generate a password
# ββ Stack lifecycle ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
docker compose up -d # start
docker compose down # stop (data kept)
docker compose down -v # β οΈ wipe everything
docker compose logs -f # live logs
docker compose ps # status
# ββ Database βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
docker exec -it documize-db mysql -u documize -p documize # MySQL shell
docker exec documize-db mysqldump -u documize -p"" documize > backup.sql
# ββ Upgrades βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
docker compose down && docker volume rm documize_app_bin && docker compose up -d
```
---
## π License
Documize Community edition is licensed under the **GNU Affero General Public License v3 (AGPL-3.0)**.
See [LICENSE](https://github.com/documize/community/blob/master/LICENSE) in the upstream repository.
This Docker configuration is provided as-is for self-hosting purposes.
---
Made with β€οΈ for the self-hosting community Β· [Documize upstream](https://github.com/documize/community) Β· [Report an issue](https://github.com/your-org/documize-docker/issues)