Skip to content
Merged

Dev #39

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
356 changes: 297 additions & 59 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -1,102 +1,340 @@
# Deployment
# Deploying Eventara on a VPS (DigitalOcean Droplet)

Deploy Eventara on any VPS with Docker.
A step‑by‑step guide to deploy Eventara on a fresh Ubuntu VPS.
Everything runs from a **single `docker compose` command** — the dashboard, API, Kafka, PostgreSQL, and Redis are all included.

## Prerequisites
---

- Docker Engine + Docker Compose plugin
- ~2 CPU / 4 GB RAM (minimum)
## Minimum Requirements

## Quick deploy
| Resource | Minimum | Recommended |
|---|---|---|
| **RAM** | 4 GB | 8 GB |
| **vCPUs** | 2 | 4 |
| **Disk** | 25 GB SSD | 50 GB SSD |
| **OS** | Ubuntu 22.04+ | Ubuntu 24.04 LTS |

> **Why 4 GB minimum?**
> Kafka alone needs ~700 MB, PostgreSQL ~500 MB, the JVM ~512 MB, plus Redis and the OS.
> With 2 GB you **will** hit OOM kills. 4 GB works for demos and light traffic (~50 events/sec).
> For production workloads (100+ events/sec), use 8 GB.

### DigitalOcean Droplet Sizes

| Droplet | RAM | vCPUs | Monthly Cost | Use Case |
|---|---|---|---|---|
| Basic $24 | 4 GB | 2 | $24/mo | Demos, dev, light production |
| Basic $48 | 8 GB | 4 | $48/mo | Production workloads |

---

## Step 1 — Install Docker

You're already SSH'd into the droplet. Run these commands:

```bash
# Update packages
sudo apt update && sudo apt upgrade -y

# Install Docker via the official convenience script
curl -fsSL https://get.docker.com | sh

# Add your user to the docker group (avoids needing sudo for docker commands)
sudo usermod -aG docker $USER

# Apply group change (or log out and back in)
newgrp docker

# Verify Docker is working
docker --version
docker compose version
```
Comment on lines +31 to +51
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guide recommends installing Docker via curl ... | sh. That’s convenient, but it’s also a known security risk (piping remote scripts to root) and can be frowned upon for production hardening.

Since this doc includes a “Production Hardening Checklist”, it would be more consistent to either:

  • include the official apt-repo installation steps (recommended), or
  • clearly label the convenience script as a fast path for demos and point production users to the official install docs.

This is documentation, but it directly impacts operator security posture.

Suggestion

Adjust Step 1 to either (a) use Docker’s official apt repository installation instructions, or (b) keep the convenience script but add a prominent note and link to the official docs.

For example, add:

Reply with "@CharlieHelps yes please" if you’d like me to add a commit updating the doc accordingly.


You should see something like:
```
Docker version 27.x.x
Docker Compose version v2.x.x
```

---

## Step 2 — Clone the Repository

```bash
cd ~
git clone https://github.com/tusharkhatriofficial/Eventara.git
cd Eventara
```

---

## Step 3 — Configure Environment Variables

```bash
git clone https://github.com/tusharkhatriofficial/eventara.git
cd eventara
cp .env.example .env
# Edit .env — at minimum change POSTGRES_PASSWORD
nano .env
```

**At minimum, change these values:**

```env
# REQUIRED — change the default password!
POSTGRES_PASSWORD=your_strong_password_here

# OPTIONAL — change the port if 8080 is taken
EVENTARA_PORT=8080

# OPTIONAL — tune JVM memory based on your droplet RAM
# For 4 GB droplet:
JAVA_OPTS=-Xms256m -Xmx512m
# For 8 GB droplet:
# JAVA_OPTS=-Xms512m -Xmx1g
```

Save and exit (`Ctrl+O`, `Enter`, `Ctrl+X` in nano).

---

## Step 4 — Build & Start

```bash
docker compose --env-file .env -f docker-compose.prod.yaml up -d --build
```

The build takes 2-5 minutes. It compiles the React dashboard and Spring Boot app into a **single container** — both API and dashboard are served on port `8080`.
**First build takes 3‑8 minutes** (downloads dependencies, compiles Java, builds React dashboard).
Subsequent deploys take ~1 minute since Docker caches layers.

---

## Step 5 — Verify Everything is Running

```bash
# Check container status
docker compose -f docker-compose.prod.yaml ps
```

You should see all 4 containers running:

```
NAME STATUS PORTS
eventara-eventara-1 Up 30 seconds 0.0.0.0:8080->8080/tcp
eventara-kafka-1 Up 45 seconds (healthy) 9092/tcp
eventara-postgres-1 Up 45 seconds (healthy) 5432/tcp
eventara-redis-1 Up 45 seconds (healthy) 6379/tcp
```

**Test the API:**

```bash
curl -s http://localhost:8080/api/v1/events \
-X POST \
-H "Content-Type: application/json" \
-d '{"eventType":"deploy.test","source":"vps","userId":"admin","severity":"INFO"}'
```

Expected response:
```json
{"eventId":"evt_...","eventType":"deploy.test","status":"accepted",...}
```

**Access from your browser:**

| What | URL |
|---|---|
| Dashboard + API | `http://<server>:8080` |
| Swagger | `http://<server>:8080/swagger-ui.html` |
| Dashboard | `http://<your-droplet-ip>:8080` |
| Swagger API Docs | `http://<your-droplet-ip>:8080/swagger-ui.html` |

---

## Common Operations

```bash
# View logs (follow mode)
docker compose -f docker-compose.prod.yaml logs -f eventara

## Coolify
# View logs for a specific service
docker compose -f docker-compose.prod.yaml logs -f kafka

1. **Add a new resource** → Docker Compose
2. Paste the contents of `docker-compose.prod.yaml` (or point it to the repo)
3. Add the environment variables from `.env.example` in the **Environment Variables** tab
4. Set the exposed port to `8080`
5. Deploy
# Restart the app (without rebuilding)
docker compose -f docker-compose.prod.yaml restart eventara

Coolify will handle the build and TLS for you.
# Stop everything
docker compose -f docker-compose.prod.yaml down

# Stop and wipe ALL data (database, kafka, redis)
docker compose -f docker-compose.prod.yaml down -v

# Rebuild after pulling new code
git pull origin main
docker compose --env-file .env -f docker-compose.prod.yaml up -d --build
```

---

## DigitalOcean / Generic Ubuntu VPS
## Setting Up a Domain with HTTPS (Optional but Recommended)

### Option A — Caddy (easiest, auto‑HTTPS)

```bash
# SSH into your droplet
ssh root@<your-ip>
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
```

# Install Docker (if not already installed)
curl -fsSL https://get.docker.com | sh
Create a Caddyfile:

# Clone and deploy
git clone https://github.com/tusharkhatriofficial/eventara.git
cd eventara
cp .env.example .env
nano .env # change POSTGRES_PASSWORD at minimum
```bash
sudo nano /etc/caddy/Caddyfile
```

```
eventara.yourdomain.com {
reverse_proxy localhost:8080
}
```

```bash
sudo systemctl restart caddy
```

That's it — Caddy automatically provisions an SSL certificate via Let's Encrypt.

### Option B — Nginx + Certbot

```bash
sudo apt install -y nginx certbot python3-certbot-nginx

sudo nano /etc/nginx/sites-available/eventara
```

```nginx
server {
server_name eventara.yourdomain.com;

location / {
proxy_pass http://localhost:8080;
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;
}

# WebSocket support for real-time dashboard
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
```

```bash
sudo ln -s /etc/nginx/sites-available/eventara /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
sudo certbot --nginx -d eventara.yourdomain.com
```

---

## Firewall Setup

Only open the ports you need:

```bash
# Allow SSH
sudo ufw allow 22

# Allow HTTP/HTTPS (for Caddy or Nginx)
sudo ufw allow 80
sudo ufw allow 443

# If accessing the app directly without a reverse proxy:
sudo ufw allow 8080

# Enable the firewall
sudo ufw enable
```

> **Important:** Do NOT open ports for Postgres (5432), Redis (6379), or Kafka (9092/9094).
> These are internal services and should never be exposed to the internet.

---

## Updating the App

When you push new code:

```bash
cd ~/Eventara
git pull origin main
docker compose --env-file .env -f docker-compose.prod.yaml up -d --build
```

## Common operations
Docker will only rebuild changed layers, so updates are much faster than the first build.

---

## Monitoring & Troubleshooting

```bash
# Logs
docker compose -f docker-compose.prod.yaml logs -f eventara
# Check which containers are running
docker compose -f docker-compose.prod.yaml ps

# Stop
docker compose -f docker-compose.prod.yaml down
# Check resource usage
docker stats --no-stream

# Check if a specific service is unhealthy
docker compose -f docker-compose.prod.yaml logs kafka --tail 50

# Check if the app started successfully
docker compose -f docker-compose.prod.yaml logs eventara --tail 100

# Restart a single service
docker compose -f docker-compose.prod.yaml restart eventara

# Wipe all data (DB + Kafka + Redis)
# Nuclear reset (wipes all data, starts fresh)
docker compose -f docker-compose.prod.yaml down -v
docker compose --env-file .env -f docker-compose.prod.yaml up -d --build
```

## Resource limits

The prod compose file sets memory limits:
### Common Issues

| Service | Memory Limit |
| Problem | Fix |
|---|---|
| Postgres | 1 GB |
| Kafka | 1 GB |
| Redis | 512 MB |
| Eventara (API + Dashboard) | 1 GB |
| `port is already allocated` | Change `EVENTARA_PORT=3000` in `.env` |
| Containers keep restarting | Check logs: `docker compose -f docker-compose.prod.yaml logs eventara` |
| Out of memory (OOM killed) | Upgrade to a larger droplet (8 GB) or reduce JVM: `JAVA_OPTS=-Xms128m -Xmx256m` |
| Kafka unhealthy | Wait 30-60 seconds, Kafka is slow to start. If persistent: `docker compose -f docker-compose.prod.yaml restart kafka` |
| Can't connect from browser | Ensure firewall allows port 8080: `sudo ufw allow 8080` |

Comment on lines +305 to +314
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The troubleshooting row suggests fixing port is already allocated by setting EVENTARA_PORT=3000, but elsewhere the document repeatedly assumes 8080 (firewall rules, URLs, reverse proxy examples). As written, a user who changes the port per this advice may end up with mismatched instructions and a broken access path.

If you want to support arbitrary ports, the doc should consistently reference ${EVENTARA_PORT} (or explicitly say “if you change it, update firewall/proxy/URLs accordingly”).

Suggestion

Make the port guidance consistent:

  • Change the fix to "Change EVENTARA_PORT to a free port (e.g. 3000)" and
  • Add a note: "If you change EVENTARA_PORT, also update UFW rules and reverse proxy upstream (e.g. reverse_proxy localhost:${EVENTARA_PORT}) and the URLs you use to access the app."

Reply with "@CharlieHelps yes please" if you’d like me to add a commit with these doc adjustments.

---

Total: ~3.5 GB. A 4 GB VPS works for demos and light use.
## Resource Limits

## Environment variables
The production compose file caps memory to prevent any single service from crashing the server:

| Variable | Default | Description |
| Service | Memory Limit | Purpose |
|---|---|---|
| `POSTGRES_USER` | `postgres` | Database user |
| `POSTGRES_PASSWORD` | `mysecretpassword` | **Change this** |
| `POSTGRES_DB` | `eventara` | Database name |
| `CLUSTER_ID` | `NvDmnaWzQgiH8qbnraqxcg` | Kafka KRaft cluster ID — don't change after first boot |
| `EVENTARA_PORT` | `8080` | Host port for the app |
| `JAVA_OPTS` | `-Xms256m -Xmx512m` | JVM memory settings |
| PostgreSQL | 1 GB | Database |
| Kafka | 1 GB | Event streaming |
| Redis | 512 MB | Caching & metrics |
| Eventara (API + Dashboard) | 1 GB | Application |
| **Total** | **~3.5 GB** | |

## Kafka (KRaft mode)
This leaves ~500 MB for the OS on a 4 GB droplet.

No Zookeeper needed. `CLUSTER_ID` must stay stable for a given Kafka data volume. If you change it, wipe the volume first (`docker compose down -v`).
---

## Production hardening checklist
## Production Hardening Checklist

- [ ] Change default database password in `.env`
- [ ] Put behind a reverse proxy (Nginx/Caddy) for TLS
- [ ] Don't expose Postgres/Redis ports to the internet (prod compose already doesn't)
- [ ] Use a managed database if scaling beyond a single node
- [ ] Changed default `POSTGRES_PASSWORD` in `.env`
- [ ] Set up a domain with HTTPS (Caddy or Nginx + Certbot)
- [ ] Enabled UFW firewall (only ports 22, 80, 443 open)
- [ ] Did NOT expose Postgres/Redis/Kafka ports to the internet
- [ ] Set up automated backups for the Postgres volume
- [ ] Tested the deployment with a test event via curl
Loading