Skip to content

πŸš€ BasicRum β€” Dokploy Deployment ​

Overview ​

We use Dokploy as a self-hosted PaaS to deploy the frontend and backend as Docker containers, with PostgreSQL and ClickHouse running as compose services.

Architecture ​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 Traefik                     β”‚
β”‚         (managed by Dokploy)                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ dev.basicrum.com β”‚ dev.basicrum.com/backend β”‚
β”‚     :3000        β”‚         :8080            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Frontend      β”‚       Backend            β”‚
β”‚   (Dockerfile)   β”‚     (Dockerfile)         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              dokploy-network                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   PostgreSQL    β”‚      ClickHouse           β”‚
β”‚     :5432       β”‚        :8123              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The dokploy app itself runs on the :3000 port but it is not mapped to the public domain. Only the frontend and backend containers are exposed publicly through Traefik.

Services ​

The frontend and backend are deployed as separate Docker containers, while PostgreSQL and ClickHouse run as compose services. The compose services are not exposed publicly and can only be accessed by the backend container over the internal dokploy-network.

PostgreSQL (Compose) ​

  • Compose file: compose/dokploy/postgres-compose.yaml
  • Container name: basicrum_postgres
  • Internal host: basicrum_postgres:5432

In the dokploy dashboard:

Select Compose path: ./compose/dokploy/postgres-compose.yaml

ClickHouse (Compose) ​

  • Compose file: compose/dokploy/clickhouse-compose.yaml
  • Container name: basicrum_clickhouse
  • Internal host: basicrum_clickhouse:8123

Screenshot of compose settings

Backend (Dockerfile) ​

The backend is built from the backend/Dockerfile and runs in a separate container. It connects to PostgreSQL and ClickHouse over the internal dokploy-network using the service names as hosts.

Screenshot of backend specific settings

Build specific settings

  • Dockerfile: backend/Dockerfile
  • Build context: ./ (repo root β€” needed for api_contract workspace dependency)
  • Port: 8080
  • Domain: dev.basicrum.com with path /backend

Domain specific settings

Note: the backend must be accessed through the full domain dev.basicrum.com/backend , since both the frontend and backend are on the same domain, any requests made to any url starting with dev.basicrum.com/backend will be routed to the backend container by Traefik. Any other urls (e.g. dev.basicrum.com/some-random-url) will be routed to the frontend container.

Environment variables ​

zsh
HOST=0.0.0.0
PORT=8080
NODE_ENV=production
PG_URL=postgresql://basicrum:basicrumXYZ%21@basicrum_postgres:5432/basicrum
CLICKHOUSE_URL=http://basicrum_clickhouse:8123
CLICKHOUSE_USER=default
CLICKHOUSE_PASSWORD=local_dev_pass
# AES-256-GCM key for encrypting org AI tokens (bring-your-own-key).
# Generate with: openssl rand -base64 32
ORG_TOKEN_ENC_KEY_V1=your_base64_32_byte_key

HOST must be 0.0.0.0 β€” otherwise the container only listens on loopback and Traefik returns 502.

Frontend (Dockerfile) ​

Frontend follows a similar setup. It is built from the frontend/Dockerfile and runs in a separate container. However, it talks to the backend by addressing it with the full qualified domain dev.basicrum.com/backend (not the internal container name) so that requests go through Traefik. (Todo: check if we can use the internal container name here to bypass Traefik and speed up requests).

  • Dockerfile: frontend/Dockerfile
  • Build context: ./ (repo root)
  • Port: 3000
  • Domain: dev.basicrum.com

Domain settings for the frontend

Environment variables ​

bash
NEXTAUTH_SECRET=<your-secret>
NEXTAUTH_URL=http://dev.basicrum.com
AUTH_TRUST_HOST=true
NEXT_PUBLIC_API_URL=https://dev.basicrum.com
BACKEND_URL_FOR_AUTH=https://dev.basicrum.com/backend/v1

Find the backend container name with: docker ps --filter "name=basicrum" --format "{{.Names}}"

Useful Commands ​

SSH into the server ​

bash
ssh <user>@<server-ip>

Check running containers ​

bash
docker ps --filter "name=basicrum" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

PostgreSQL ​

Connect to psql:

bash
docker exec -it basicrum_postgres psql -U basicrum -d basicrum

List tables:

sql
\dt

Inspect a table:

sql
\d users

Query rows:

sql
SELECT * FROM users;
SELECT * FROM organizations;

Delete a user:

sql
DELETE FROM users WHERE email = 'user@example.com';

ClickHouse ​

Connect to clickhouse-client:

bash
docker exec -it basicrum_clickhouse clickhouse-client

List tables:

sql
SHOW TABLES;

View container logs ​

bash
docker logs -f basicrum_postgres
docker logs -f basicrum_clickhouse
docker logs -f <backend-container-name>
docker logs -f <frontend-container-name>

Restart a container ​

bash
docker restart <container-name>

Check Docker networks ​

bash
docker network inspect dokploy-network