build 2
This commit is contained in:
58
Dockerfile
Normal file
58
Dockerfile
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# ── Stage 1: Build frontend ───────────────────────────────────────────────────
|
||||||
|
FROM node:20-slim AS frontend-builder
|
||||||
|
|
||||||
|
WORKDIR /build/frontend
|
||||||
|
COPY frontend/package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY frontend/ ./
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ── Stage 2: Build backend ────────────────────────────────────────────────────
|
||||||
|
FROM node:20-slim AS backend-builder
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
python3 make g++ \
|
||||||
|
--no-install-recommends \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /build/backend
|
||||||
|
COPY backend/package*.json backend/tsconfig.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY backend/src ./src
|
||||||
|
RUN npm run build && npm prune --production
|
||||||
|
|
||||||
|
# ── Stage 3: Runtime ─────────────────────────────────────────────────────────
|
||||||
|
FROM node:20-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
nginx \
|
||||||
|
chromium \
|
||||||
|
fonts-freefont-ttf \
|
||||||
|
supervisor \
|
||||||
|
--no-install-recommends \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3001
|
||||||
|
ENV DATABASE_PATH=/app/data/tracker.db
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Backend
|
||||||
|
COPY --from=backend-builder /build/backend/dist ./backend/dist
|
||||||
|
COPY --from=backend-builder /build/backend/node_modules ./backend/node_modules
|
||||||
|
COPY backend/package.json ./backend/
|
||||||
|
|
||||||
|
# Frontend → nginx web root
|
||||||
|
COPY --from=frontend-builder /build/frontend/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Config files
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
|
||||||
|
# Persistent data volume
|
||||||
|
VOLUME ["/app/data"]
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||||
223
UNRAID.md
Normal file
223
UNRAID.md
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
# Unraid Installation Guide — UI Stock Tracker
|
||||||
|
|
||||||
|
UI Stock Tracker runs as a **single Docker container** — nginx serves the frontend and proxies API calls to the Node.js backend, both managed inside the container by supervisord.
|
||||||
|
|
||||||
|
Two installation methods are covered: **CLI via SSH** (recommended) and **GUI via Compose Manager**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Unraid 6.10 or later
|
||||||
|
- Docker enabled: **Settings → Docker → Enable Docker → Yes**
|
||||||
|
- A share to store the persistent SQLite database (e.g. `/mnt/user/appdata/ui-tracker/data`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 1 — CLI via SSH (Recommended)
|
||||||
|
|
||||||
|
### 1. SSH into your Unraid server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@<your-unraid-ip>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Copy the project files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /mnt/user/appdata/ui-tracker
|
||||||
|
cd /mnt/user/appdata/ui-tracker
|
||||||
|
git clone https://github.com/<your-username>/ui-tracker.git .
|
||||||
|
```
|
||||||
|
|
||||||
|
> No git? Copy the folder via SMB (`\\<unraid-ip>\appdata`) or SFTP instead.
|
||||||
|
|
||||||
|
### 3. Build and start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
The first build takes a few minutes — it compiles both the React frontend and the Node.js backend, then installs Chromium. Subsequent starts are instant.
|
||||||
|
|
||||||
|
### 4. Verify it's running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
```
|
||||||
|
NAME STATUS
|
||||||
|
ui-tracker running
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Open the web UI
|
||||||
|
|
||||||
|
```
|
||||||
|
http://<your-unraid-ip>:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### Useful commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Live logs (nginx + backend combined)
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Restart the container
|
||||||
|
docker compose restart
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
# Rebuild after updating the code
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Method 2 — GUI via Compose Manager Plugin
|
||||||
|
|
||||||
|
### 1. Install Compose Manager
|
||||||
|
|
||||||
|
1. Go to **Apps** (Community Applications)
|
||||||
|
2. Search for **Compose Manager** and install it
|
||||||
|
3. It appears under **Docker → Compose**
|
||||||
|
|
||||||
|
### 2. Upload the project files
|
||||||
|
|
||||||
|
Copy the `ui-tracker` folder to your Unraid server at:
|
||||||
|
|
||||||
|
```
|
||||||
|
/mnt/user/appdata/ui-tracker/
|
||||||
|
```
|
||||||
|
|
||||||
|
Use any of: SMB share (`\\<unraid-ip>\appdata`), SFTP (FileZilla / WinSCP), or the Unraid **Tools → File Manager**.
|
||||||
|
|
||||||
|
### 3. Add the stack
|
||||||
|
|
||||||
|
1. Go to **Docker → Compose → Add New Stack**
|
||||||
|
2. Name: `ui-tracker`
|
||||||
|
3. Compose file path: `/mnt/user/appdata/ui-tracker/docker-compose.yml`
|
||||||
|
4. Click **Save**
|
||||||
|
|
||||||
|
### 4. Build and start
|
||||||
|
|
||||||
|
1. Expand the `ui-tracker` stack row
|
||||||
|
2. Click **Build** (takes a few minutes on first run)
|
||||||
|
3. Click **Start**
|
||||||
|
|
||||||
|
### 5. Open the web UI
|
||||||
|
|
||||||
|
```
|
||||||
|
http://<your-unraid-ip>:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Manual Docker Run (No Compose)
|
||||||
|
|
||||||
|
If you prefer to run it without docker-compose:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t ui-tracker /mnt/user/appdata/ui-tracker
|
||||||
|
|
||||||
|
docker run -d \
|
||||||
|
--name ui-tracker \
|
||||||
|
--restart unless-stopped \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-v /mnt/user/appdata/ui-tracker/data:/app/data \
|
||||||
|
ui-tracker
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Container Internals
|
||||||
|
|
||||||
|
| Process | Role |
|
||||||
|
|-----------|------------------------------------------------|
|
||||||
|
| supervisord | Process manager — keeps both services alive |
|
||||||
|
| nginx | Serves the React frontend on port 8080, proxies `/api/` to Node.js |
|
||||||
|
| node | Express API + Puppeteer scraper + scheduler |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Port Reference
|
||||||
|
|
||||||
|
| Host Port | Purpose |
|
||||||
|
|-----------|----------------------------------|
|
||||||
|
| **8080** | Web UI (only port you need open) |
|
||||||
|
|
||||||
|
> To use a different port, change `"8080:8080"` to `"<port>:8080"` in `docker-compose.yml` before building.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Persistence
|
||||||
|
|
||||||
|
The SQLite database lives at:
|
||||||
|
|
||||||
|
```
|
||||||
|
/mnt/user/appdata/ui-tracker/data/tracker.db
|
||||||
|
```
|
||||||
|
|
||||||
|
It is mounted into the container via the volume in `docker-compose.yml`. All tracked items and Telegram settings survive container restarts, rebuilds, and updates.
|
||||||
|
|
||||||
|
**Backup:**
|
||||||
|
```bash
|
||||||
|
cp /mnt/user/appdata/ui-tracker/data/tracker.db ~/tracker-backup.db
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## First-Time Setup
|
||||||
|
|
||||||
|
Once the UI is open:
|
||||||
|
|
||||||
|
1. Click **Settings** (top right)
|
||||||
|
2. Enter your **Bot Token**: `8769097441:AAFBqPlSTcTIi3I-F5ZIN9EEpwbNDzHg8hM`
|
||||||
|
3. Enter your **Chat ID**: `8435449432`
|
||||||
|
4. Click **Test Alert** — a Telegram message should arrive within seconds
|
||||||
|
5. Click **Save**
|
||||||
|
6. Click **Add Item**, paste a `store.ui.com` product URL, set your check interval, click **Start Tracking**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**UI shows "Cannot reach backend"**
|
||||||
|
```bash
|
||||||
|
docker logs ui-tracker
|
||||||
|
```
|
||||||
|
Look for Node.js startup errors. The backend starts on port 3001 internally — nginx proxies to it.
|
||||||
|
|
||||||
|
**Telegram test fails**
|
||||||
|
- Verify the bot token and chat ID in Settings
|
||||||
|
- Send `/start` to your bot in Telegram at least once to open the conversation
|
||||||
|
- Confirm Unraid has outbound HTTPS access (port 443)
|
||||||
|
|
||||||
|
**Items stuck on "Unknown" status**
|
||||||
|
```bash
|
||||||
|
docker logs ui-tracker | grep Scheduler
|
||||||
|
```
|
||||||
|
Puppeteer errors here usually mean Chromium failed to launch. Try restarting:
|
||||||
|
```bash
|
||||||
|
docker compose restart
|
||||||
|
```
|
||||||
|
|
||||||
|
**Port 8080 already in use**
|
||||||
|
```bash
|
||||||
|
netstat -tulnp | grep 8080
|
||||||
|
```
|
||||||
|
Change the host port in `docker-compose.yml` and rebuild.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /mnt/user/appdata/ui-tracker
|
||||||
|
git pull
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
The database and all your settings are preserved.
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# ── Build stage ──────────────────────────────────────────────────────────────
|
|
||||||
FROM node:20-slim AS builder
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
python3 make g++ \
|
|
||||||
--no-install-recommends \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY package*.json tsconfig.json ./
|
|
||||||
RUN npm ci
|
|
||||||
|
|
||||||
COPY src ./src
|
|
||||||
RUN npm run build && npm prune --production
|
|
||||||
|
|
||||||
# ── Runtime stage ─────────────────────────────────────────────────────────────
|
|
||||||
FROM node:20-slim
|
|
||||||
|
|
||||||
# Install Chromium and runtime dependencies
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
chromium \
|
|
||||||
fonts-freefont-ttf \
|
|
||||||
--no-install-recommends \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY --from=builder /app/dist ./dist
|
|
||||||
COPY --from=builder /app/node_modules ./node_modules
|
|
||||||
COPY package.json ./
|
|
||||||
|
|
||||||
EXPOSE 3001
|
|
||||||
CMD ["node", "dist/index.js"]
|
|
||||||
@@ -1,25 +1,11 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
backend:
|
ui-tracker:
|
||||||
build: ./backend
|
build: .
|
||||||
container_name: ui-tracker-backend
|
container_name: ui-tracker
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "3001:3001"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- ./data:/app/data
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- PORT=3001
|
|
||||||
- DATABASE_PATH=/app/data/tracker.db
|
|
||||||
- PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
build: ./frontend
|
|
||||||
container_name: ui-tracker-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# ── Build stage ──────────────────────────────────────────────────────────────
|
|
||||||
FROM node:20-slim AS builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY package*.json ./
|
|
||||||
RUN npm ci
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# ── Runtime stage ─────────────────────────────────────────────────────────────
|
|
||||||
FROM nginx:stable-alpine
|
|
||||||
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 8080;
|
||||||
server_name _;
|
server_name _;
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
@@ -10,9 +10,9 @@ server {
|
|||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Proxy API requests to backend
|
# Proxy API requests to the Node.js backend running in the same container
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://ui-tracker-backend:3001;
|
proxy_pass http://127.0.0.1:3001;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
26
supervisord.conf
Normal file
26
supervisord.conf
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
pidfile=/tmp/supervisord.pid
|
||||||
|
user=root
|
||||||
|
|
||||||
|
[program:nginx]
|
||||||
|
command=/usr/sbin/nginx -g "daemon off;"
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
autorestart=true
|
||||||
|
priority=10
|
||||||
|
|
||||||
|
[program:backend]
|
||||||
|
command=node /app/backend/dist/index.js
|
||||||
|
directory=/app/backend
|
||||||
|
environment=NODE_ENV="production",PORT="3001",DATABASE_PATH="/app/data/tracker.db",PUPPETEER_EXECUTABLE_PATH="/usr/bin/chromium"
|
||||||
|
stdout_logfile=/dev/stdout
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
stderr_logfile=/dev/stderr
|
||||||
|
stderr_logfile_maxbytes=0
|
||||||
|
autorestart=true
|
||||||
|
priority=20
|
||||||
Reference in New Issue
Block a user