Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/smoke-test-services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- name: Start infrastructure services
working-directory: on-prem
run: |
echo "Starting Redis and MongoDB..."
echo "Starting Redis, MongoDB, and MongoDB init..."
docker compose -f docker-compose.full.yml up -d redis mongodb
echo "Waiting for services to initialize..."

Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Docker Compose configuration for self-hosted Currents deployment.
## Quick Setup

```bash
git clone https://github.com/currents-dev/currents-dev-docker.git
cd currents-dev-docker/on-prem
git clone https://github.com/currents-dev/docker.git currents-docker
cd currents-docker/on-prem
./scripts/setup.sh
docker compose up -d
```
Expand Down
124 changes: 121 additions & 3 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ This guide walks you through setting up Currents on-premises using Docker Compos
## Step 1: Clone the Repository

```bash
git clone https://github.com/currents-dev/currents-dev-docker.git
cd currents-dev-docker/on-prem
git clone https://github.com/currents-dev/docker.git currents-docker
cd currents-docker/on-prem
```

## Step 2: Create Environment File
Expand Down Expand Up @@ -188,9 +188,11 @@ CURRENTS_RECORD_API_URL=https://currents-record.example.com
### Using the Included Traefik Profile

1. Place your wildcard certificate files in `data/traefik/certs/`:
- `wildcard.crt` - Certificate file
- `wildcard.crt` - **Fullchain** certificate file (server cert + intermediate certs concatenated)
- `wildcard.key` - Private key file

> **Important:** The `wildcard.crt` must be a fullchain certificate containing your server certificate followed by intermediate certificate(s). Without the full chain, clients will fail with "unable to verify certificate" errors. You can create it by concatenating: `cat server.crt intermediate.crt > wildcard.crt`

2. Configure your domain in `.env`:
```bash
TRAEFIK_DOMAIN=example.com
Expand Down Expand Up @@ -272,6 +274,122 @@ DC_API_PORT=4001
DC_DIRECTOR_PORT=1235
```

### Podman: Permission Denied Errors

If you're using Podman and see permission errors like:
```
mongodb-1 | chown: changing ownership of '/data/db': Permission denied
mongodb-1 | bash: /data/db/replica.key: Permission denied
```

This is due to Podman's rootless mode and UID mapping. Follow these steps:

#### Step 1: Create Data Directories

Create the data directories manually before starting services:

```bash
mkdir -p data/mongodb data/redis data/clickhouse data/rustfs data/startup data/traefik/certs data/traefik/config
```

#### Step 2: Set Permissions

Set ownership to match container UIDs:

For **rootless Podman** (running as a regular user):
```bash
# MongoDB runs as uid 999
podman unshare chown -R 999:999 data/mongodb

# ClickHouse runs as uid 101
podman unshare chown -R 101:101 data/clickhouse

# Redis runs as uid 999
podman unshare chown -R 999:999 data/redis

# RustFS runs as uid 10001 (if using local object storage)
podman unshare chown -R 10001:10001 data/rustfs

# Scheduler runs as uid 1000
podman unshare chown -R 1000:1000 data/startup

# Traefik runs as root (uid 0) - no chown needed, just create dirs
```

For **rootful Podman** (running as root or with sudo):
```bash
# MongoDB runs as uid 999
sudo chown -R 999:999 data/mongodb

# ClickHouse runs as uid 101
sudo chown -R 101:101 data/clickhouse

# Redis runs as uid 999
sudo chown -R 999:999 data/redis

# RustFS runs as uid 10001 (if using local object storage)
sudo chown -R 10001:10001 data/rustfs

# Scheduler runs as uid 1000
sudo chown -R 1000:1000 data/startup

# Traefik runs as root (uid 0) - no chown needed
```

> **Tip:** To check if you're running rootless Podman, run `podman info --format '{{.Host.Security.Rootless}}'`. If it returns `true`, use `podman unshare`; otherwise use `sudo chown`.

#### Step 3: SELinux (RHEL/CentOS/Fedora)

If SELinux is enabled, you need to relabel the data directories so containers can access them:

```bash
# Relabel data directories for container access
sudo chcon -Rt svirt_sandbox_file_t data/
```

Or for each directory individually:
```bash
sudo chcon -Rt svirt_sandbox_file_t data/mongodb
sudo chcon -Rt svirt_sandbox_file_t data/redis
sudo chcon -Rt svirt_sandbox_file_t data/clickhouse
sudo chcon -Rt svirt_sandbox_file_t data/rustfs
sudo chcon -Rt svirt_sandbox_file_t data/startup
sudo chcon -Rt svirt_sandbox_file_t data/traefik
```

To verify the labels are set correctly:
```bash
ls -lZ data/
```

You should see `svirt_sandbox_file_t` in the output.

#### Alternative: Use Named Volumes

Named volumes avoid permission issues entirely since Podman manages them:

```bash
# Create named volumes
podman volume create mongodb-data
podman volume create redis-data
podman volume create clickhouse-data
podman volume create rustfs-data
podman volume create scheduler-startup
podman volume create traefik-certs
podman volume create traefik-config

# Configure in .env
DC_MONGODB_VOLUME=mongodb-data
DC_REDIS_VOLUME=redis-data
DC_CLICKHOUSE_VOLUME=clickhouse-data
DC_RUSTFS_VOLUME=rustfs-data
DC_SCHEDULER_STARTUP_VOLUME=scheduler-startup
DC_TRAEFIK_CERTS_DIR=traefik-certs
DC_TRAEFIK_CONFIG_DIR=traefik-config
```

> **Note:** Named volumes are stored in Podman's volume directory (typically `~/.local/share/containers/storage/volumes/`) rather than the current directory.

## Advanced: Port Binding Configuration

By default, application ports (API, Director) bind to all interfaces while database ports bind to localhost only. You can customize this behavior using `DC_*_PORT` variables.
Expand Down
39 changes: 15 additions & 24 deletions on-prem/docker-compose.database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,33 +226,24 @@ services:
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD}
networks:
- default
post_start:
- command:
- bash
- -c
- |
echo 'Waiting for MongoDB to be ready...'
until mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --quiet --eval "db.adminCommand('ping')" 2>/dev/null; do sleep 1; done

echo 'Initializing replica set...'
mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --quiet --eval "
try {
rs.status();
print('Replica set already initialized');
} catch (err) {
rs.initiate({_id:'rs0', members:[{_id:0, host:'mongodb:27017'}]});
print('Replica set initialized');
}
"

echo 'MongoDB initialization complete'
healthcheck:
test:
- 'CMD-SHELL'
- mongosh --quiet --eval "db.runCommand('ping').ok" localhost:27017
- CMD-SHELL
- |
mongosh -u "$$MONGO_INITDB_ROOT_USERNAME" -p "$$MONGO_INITDB_ROOT_PASSWORD" --authenticationDatabase admin --quiet --eval "
try {
const status = rs.status();
if (status.myState === 1) { quit(0); }
quit(1);
} catch (err) {
if (err.codeName === 'NotYetInitialized') {
rs.initiate({_id:'rs0', members:[{_id:0, host:'mongodb:27017'}]});
}
quit(1);
}"
interval: 5s
timeout: 5s
retries: 10
timeout: 10s
retries: 30
start_period: 10s
volumes:
- ${DC_MONGODB_VOLUME:-./data/mongodb}:/data/db
Expand Down
39 changes: 15 additions & 24 deletions on-prem/docker-compose.full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,33 +233,24 @@ services:
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD}
networks:
- default
post_start:
- command:
- bash
- -c
- |
echo 'Waiting for MongoDB to be ready...'
until mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --quiet --eval "db.adminCommand('ping')" 2>/dev/null; do sleep 1; done

echo 'Initializing replica set...'
mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --quiet --eval "
try {
rs.status();
print('Replica set already initialized');
} catch (err) {
rs.initiate({_id:'rs0', members:[{_id:0, host:'mongodb:27017'}]});
print('Replica set initialized');
}
"

echo 'MongoDB initialization complete'
healthcheck:
test:
- 'CMD-SHELL'
- mongosh --quiet --eval "db.runCommand('ping').ok" localhost:27017
- CMD-SHELL
- |
mongosh -u "$$MONGO_INITDB_ROOT_USERNAME" -p "$$MONGO_INITDB_ROOT_PASSWORD" --authenticationDatabase admin --quiet --eval "
try {
const status = rs.status();
if (status.myState === 1) { quit(0); }
quit(1);
} catch (err) {
if (err.codeName === 'NotYetInitialized') {
rs.initiate({_id:'rs0', members:[{_id:0, host:'mongodb:27017'}]});
}
quit(1);
}"
interval: 5s
timeout: 5s
retries: 10
timeout: 10s
retries: 30
start_period: 10s
volumes:
- ${DC_MONGODB_VOLUME:-./data/mongodb}:/data/db
Expand Down
39 changes: 15 additions & 24 deletions on-prem/templates/compose.mongodb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,24 @@ services:
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD}
networks:
- default
post_start:
- command:
- bash
- -c
- |
echo 'Waiting for MongoDB to be ready...'
until mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --quiet --eval "db.adminCommand('ping')" 2>/dev/null; do sleep 1; done

echo 'Initializing replica set...'
mongosh -u $$MONGO_INITDB_ROOT_USERNAME -p $$MONGO_INITDB_ROOT_PASSWORD --authenticationDatabase admin --quiet --eval "
try {
rs.status();
print('Replica set already initialized');
} catch (err) {
rs.initiate({_id:'rs0', members:[{_id:0, host:'mongodb:27017'}]});
print('Replica set initialized');
}
"

echo 'MongoDB initialization complete'
healthcheck:
test:
- 'CMD-SHELL'
- mongosh --quiet --eval "db.runCommand('ping').ok" localhost:27017
- CMD-SHELL
- |
mongosh -u "$$MONGO_INITDB_ROOT_USERNAME" -p "$$MONGO_INITDB_ROOT_PASSWORD" --authenticationDatabase admin --quiet --eval "
try {
const status = rs.status();
if (status.myState === 1) { quit(0); }
quit(1);
} catch (err) {
if (err.codeName === 'NotYetInitialized') {
rs.initiate({_id:'rs0', members:[{_id:0, host:'mongodb:27017'}]});
}
quit(1);
}"
interval: 5s
timeout: 5s
retries: 10
timeout: 10s
retries: 30
start_period: 10s
volumes:
- ${DC_MONGODB_VOLUME:-./data/mongodb}:/data/db
Expand Down