Skip to content
Open
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
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.2.1] - 2026-05-18

### Fixed

- **Podman compatibility — Docker socket**: `docker compose` failed with `FileNotFoundError` because the
Podman socket (`/run/user/<uid>/podman/podman.sock`) was inactive. Fix: enable and start
`systemctl --user start podman.socket` and export
`DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock`.
- **Podman compatibility — unqualified image names**: Podman rootless mode does not resolve short image
names without a registry prefix. Updated all `FROM` directives in `Dockerfile` and
`dashboard/Dockerfile` to use fully-qualified names (`docker.io/node:22-slim`,
`docker.io/node:20-alpine`, `docker.io/nginx:alpine`).
- **Healthcheck crash on Node 22**: `node -e "require('http').get(..., (r) => ...)"` failed inside the
container because Node 22 routes `node -e` through its TypeScript evaluator (`evalTypeScript`) which
rejects arrow-function syntax, and Podman further splits the quoted shell command on whitespace causing
`SyntaxError: Unexpected end of input`. Fixed by installing `curl` in the production stage and
replacing both the `Dockerfile` `HEALTHCHECK` and the `docker-compose.dev.yml` `test` with
`curl -f http://localhost:2785/api/health`.

### Changed

- **Dockerfile** (`production` stage): Added `curl` to `apt-get install` for use by the healthcheck.
- **docker-compose.dev.yml**: Simplified healthcheck `test` from a multi-token `node -e` array to
`['CMD', 'curl', '-f', 'http://localhost:2785/api/health']`.

## [0.1.6] - 2026-05-17

### Fixed
Expand Down
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Multi-stage build for production-ready image

# ===== Stage 1: Builder =====
FROM node:22-slim AS builder
FROM docker.io/node:22-slim AS builder

WORKDIR /app

Expand All @@ -26,7 +26,7 @@ COPY . .
RUN npm run build

# ===== Stage 2: Production =====
FROM node:22-slim AS production
FROM docker.io/node:22-slim AS production

# Install Chrome/Chromium and required dependencies
RUN apt-get update && apt-get install -y \
Expand All @@ -49,6 +49,7 @@ RUN apt-get update && apt-get install -y \
libxrandr2 \
xdg-utils \
dumb-init \
curl \
&& rm -rf /var/lib/apt/lists/*

# Set Chrome executable path for Puppeteer
Expand Down Expand Up @@ -82,7 +83,7 @@ EXPOSE 2785

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD node -e "require('http').get('http://localhost:2785/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
CMD curl -f http://localhost:2785/api/health || exit 1

# Start with dumb-init to handle signals properly
ENTRYPOINT ["dumb-init", "--"]
Expand Down
64 changes: 59 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@
</p>

<p align="center">
<img src="https://img.shields.io/badge/version-0.1.6-blue.svg" alt="Version"/>
<img src="https://img.shields.io/badge/version-0.2.1-blue.svg" alt="Version"/>
<img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"/>
<img src="https://img.shields.io/badge/node-22_LTS-brightgreen.svg" alt="Node"/>
<img src="https://img.shields.io/badge/NestJS-11.x-red.svg" alt="NestJS"/>
<img src="https://img.shields.io/badge/docker-ready-blue.svg" alt="Docker"/>
<img src="https://img.shields.io/badge/TypeScript-5.x-3178C6.svg" alt="TypeScript"/>
<img src="https://img.shields.io/badge/Docker%20Hub-3bsalam%2Fopenwa-blue?logo=docker" alt="Docker Hub"/>
</p>

---
Expand Down Expand Up @@ -94,11 +95,53 @@ Built on a **pluggable architecture**, OpenWA lets you swap database engines (SQ

## 🚀 Quick Start

### Option A: Docker (Recommended)
### Option A: Docker Hub — Pre-built Images (Fastest)

No need to clone or build. Three commands and you're running:

```bash
# 1. Create a project folder
mkdir openwa && cd openwa

# 2. Download the compose file and default config
curl -o docker-compose.hub.yml https://raw.githubusercontent.com/3bsalam-1/OpenWA/main/docker-compose.hub.yml
curl -o .env https://raw.githubusercontent.com/3bsalam-1/OpenWA/main/.env.example

# 3. (Optional) Edit .env to customise ports, database, storage, etc.
# nano .env

# 4. Start
docker compose -f docker-compose.hub.yml up -d
```

Once running:

| URL | Description |
| --- | --- |
| `http://localhost:2886` | Dashboard |
| `http://localhost:2785/api` | REST API |
| `http://localhost:2785/api/docs` | Swagger docs |

The API key is printed in the container logs on first boot:

```bash
docker logs openwa-api | grep "API Key"
```

**Available images:**

| Image | Tag |
| --- | --- |
| `3bsalam/openwa-api` | `latest`, `0.2.1` |
| `3bsalam/openwa-dashboard` | `latest`, `0.2.1` |

---

### Option B: Build from Source

```bash
# Clone and start
git clone https://github.com/rmyndharis/OpenWA.git
git clone https://github.com/3bsalam-1/OpenWA.git
cd OpenWA
docker compose -f docker-compose.dev.yml up -d

Expand All @@ -108,11 +151,22 @@ docker compose -f docker-compose.dev.yml up -d
# Swagger: http://localhost:2785/api/docs
```

### Option B: Local Development
> **Using Podman instead of Docker?**
> Podman rootless mode requires the socket to be running and `DOCKER_HOST` to be set:
>
> ```bash
> systemctl --user start podman.socket
> systemctl --user enable podman.socket
> export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock
> ```
>
> Add the `export` line to your `~/.bashrc` to make it permanent.

### Option C: Local Development

```bash
# Clone repository
git clone https://github.com/rmyndharis/OpenWA.git
git clone https://github.com/3bsalam-1/OpenWA.git
cd OpenWA

# Install dependencies (includes dashboard)
Expand Down
4 changes: 2 additions & 2 deletions dashboard/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:20-alpine AS builder
FROM docker.io/node:20-alpine AS builder

WORKDIR /app

Expand All @@ -15,7 +15,7 @@ COPY . .
RUN npm run build

# Production stage with nginx
FROM nginx:alpine
FROM docker.io/nginx:alpine

# Copy built files
COPY --from=builder /app/dist /usr/share/nginx/html
Expand Down
8 changes: 1 addition & 7 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@ services:
- ./data:/app/data
restart: unless-stopped
healthcheck:
test:
[
'CMD',
'node',
'-e',
"require('http').get('http://localhost:2785/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))",
]
test: ['CMD', 'curl', '-f', 'http://localhost:2785/api/health']
interval: 30s
timeout: 10s
retries: 3
Expand Down
75 changes: 75 additions & 0 deletions docker-compose.hub.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# OpenWA - Docker Compose using pre-built Docker Hub images
# Quick Start:
# cp .env.example .env # then edit .env as needed
# docker compose -f docker-compose.hub.yml up -d

services:
openwa:
image: 3bsalam/openwa-api:latest
container_name: openwa-api
ports:
- '127.0.0.1:${API_PORT:-2785}:2785'
environment:
# Core
- NODE_ENV=${NODE_ENV:-production}
- PORT=2785
- LOG_LEVEL=${LOG_LEVEL:-info}
# Database
- DATABASE_TYPE=${DATABASE_TYPE:-sqlite}
- DATABASE_NAME=${DATABASE_NAME:-/app/data/openwa.sqlite}
- DATABASE_HOST=${DATABASE_HOST:-postgres}
- DATABASE_PORT=${DATABASE_PORT:-5432}
- DATABASE_USERNAME=${DATABASE_USERNAME:-openwa}
- DATABASE_PASSWORD=${DATABASE_PASSWORD:-openwa}
- DATABASE_SYNCHRONIZE=${DATABASE_SYNCHRONIZE:-false}
# Engine
- ENGINE_TYPE=${ENGINE_TYPE:-whatsapp-web.js}
- SESSION_DATA_PATH=/app/data/sessions
- PUPPETEER_HEADLESS=${PUPPETEER_HEADLESS:-true}
- PUPPETEER_ARGS=${PUPPETEER_ARGS:---no-sandbox,--disable-setuid-sandbox,--disable-dev-shm-usage,--disable-gpu}
# Storage
- STORAGE_TYPE=${STORAGE_TYPE:-local}
- STORAGE_LOCAL_PATH=/app/data/media
- S3_ENDPOINT=${S3_ENDPOINT:-http://minio:9000}
- S3_ACCESS_KEY=${S3_ACCESS_KEY:-minioadmin}
- S3_SECRET_KEY=${S3_SECRET_KEY:-minioadmin}
- S3_BUCKET=${S3_BUCKET:-openwa}
# Redis
- REDIS_ENABLED=${REDIS_ENABLED:-false}
- REDIS_HOST=${REDIS_HOST:-redis}
- REDIS_PORT=${REDIS_PORT:-6379}
# Webhook
- WEBHOOK_TIMEOUT=${WEBHOOK_TIMEOUT:-10000}
- WEBHOOK_MAX_RETRIES=${WEBHOOK_MAX_RETRIES:-3}
- WEBHOOK_RETRY_DELAY=${WEBHOOK_RETRY_DELAY:-5000}
# Rate Limiting
- RATE_LIMIT_TTL=${RATE_LIMIT_TTL:-60}
- RATE_LIMIT_MAX=${RATE_LIMIT_MAX:-100}
# Plugins
- PLUGINS_ENABLED=${PLUGINS_ENABLED:-true}
- PLUGINS_DIR=/app/data/plugins
# Security
- API_MASTER_KEY=${API_MASTER_KEY:-}
volumes:
- ./data:/app/data
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:2785/api/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 30s

dashboard:
image: 3bsalam/openwa-dashboard:latest
container_name: openwa-dashboard
ports:
- '127.0.0.1:${DASHBOARD_PORT:-2886}:80'
depends_on:
openwa:
condition: service_healthy
restart: unless-stopped

networks:
default:
name: openwa-network
80 changes: 79 additions & 1 deletion docs/12-troubleshooting-faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,85 @@ flowchart TD
A3 -->|No| A3a[Check message format]
```

## 12.2 Connection Issues
## 12.2 Podman Compatibility

### Issue: `FileNotFoundError` / Docker socket missing

**Symptoms:**

```text
docker.errors.DockerException: Error while fetching server API version:
('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))
```

**Cause:** The system uses Podman (not Docker Engine). Podman's rootless socket is inactive by default.

**Fix:**

```bash
systemctl --user start podman.socket
systemctl --user enable podman.socket
export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock
```

Add the `export` to `~/.bashrc` to make it permanent.

---

### Issue: `short-name did not resolve to an alias`

**Symptoms:**

```text
Error: creating build container: short-name "nginx:alpine" did not resolve to an alias
and no unqualified-search registries are defined
```

**Cause:** Podman rootless mode does not fall back to Docker Hub for unqualified image names.

**Fix:** All `FROM` directives in `Dockerfile` and `dashboard/Dockerfile` must use fully-qualified names:

```dockerfile
FROM docker.io/node:22-slim
FROM docker.io/nginx:alpine
```

---

### Issue: Healthcheck always `unhealthy` on Node 22 + Podman

**Symptoms:** Container starts successfully but stays `unhealthy`; logs show:

```text
SyntaxError: Unexpected end of input
at evalTypeScript (node:internal/process/execution:256:22)
```

**Cause:** Node 22 routes `node -e` through its TypeScript evaluator which rejects arrow-function
syntax. Podman also splits quoted shell commands on whitespace, truncating the `-e` argument.

**Fix:** Use `curl` for the healthcheck instead of `node -e`:

```dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:2785/api/health || exit 1
```

```yaml
# docker-compose.dev.yml
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:2785/api/health']
```

Ensure `curl` is installed in the production stage:

```dockerfile
RUN apt-get install -y ... curl ...
```

---

## 12.3 Connection Issues

### Issue: Container Won't Start

Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
</p>

<p align="center">
<img src="https://img.shields.io/badge/version-0.1.6-blue.svg" alt="Version"/>
<img src="https://img.shields.io/badge/version-0.2.1-blue.svg" alt="Version"/>
<img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"/>
<img src="https://img.shields.io/badge/node-20_LTS-brightgreen.svg" alt="Node"/>
<img src="https://img.shields.io/badge/node-22_LTS-brightgreen.svg" alt="Node"/>
<img src="https://img.shields.io/badge/NestJS-11.x-red.svg" alt="NestJS"/>
<img src="https://img.shields.io/badge/docker-ready-blue.svg" alt="Docker"/>
<img src="https://img.shields.io/badge/TypeScript-5.x-3178C6.svg" alt="TypeScript"/>
Expand Down