Compare commits

...

3 Commits

Author SHA1 Message Date
Tomas Dvorak 23ec4749ab feat(ci): add deployment guides and docker-compose configurations
Docker Build / build (push) Failing after 10m7s
Add docker-compose files for CasaOS and Dokploy deployment scenarios,
update README with deployment instructions, and add 'latest' tag support
to the docker-build workflow.
2026-05-07 10:44:33 +02:00
Tomas Dvorak 7051459017 ci/cd 2026-05-07 10:17:07 +02:00
Tomas Dvorak b7d86ad5f8 ci(docker): add support for Gitea registry and update permissions
Update the docker-build workflow to support both GitHub Container Registry
and Gitea by dynamically determining the registry URL based on the
server URL. Added explicit permissions for package writing and implemented
conditional login steps to handle GitHub and Gitea authentication
differently.
2026-05-07 09:47:56 +02:00
7 changed files with 313 additions and 57 deletions
+20 -44
View File
@@ -8,11 +8,15 @@ on:
branches: [main] branches: [main]
env: env:
REGISTRY: ghcr.io REGISTRY: ${{ github.server_url == 'https://github.com' && 'ghcr.io' || format('{0}/v2', github.server_url) }}
IMAGE_PREFIX: ${{ github.repository }} IMAGE_PREFIX: ${{ github.repository }}
permissions:
contents: read
packages: write
jobs: jobs:
build-backend: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -20,66 +24,38 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Log in to registry (push only) - name: Log in to registry (push only) - GitHub
if: github.event_name == 'push' if: github.event_name == 'push' && github.server_url == 'https://github.com'
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to registry (push only) - Gitea
if: github.event_name == 'push' && github.server_url != 'https://github.com'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.GITEA_USERNAME || github.actor }}
password: ${{ secrets.GITEA_TOKEN || secrets.GITHUB_TOKEN }}
- name: Extract metadata - name: Extract metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/backend images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}
tags: | tags: |
type=ref,event=branch type=ref,event=branch
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=sha type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push backend image - name: Build and push image
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
context: . context: .
file: backend/Dockerfile file: Dockerfile
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry (push only)
if: github.event_name == 'push'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/frontend
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha
- name: Build and push frontend image
uses: docker/build-push-action@v6
with:
context: ./frontend
file: frontend/Dockerfile
push: ${{ github.event_name == 'push' }} push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
+57
View File
@@ -0,0 +1,57 @@
# Build stage for frontend
FROM node:22-alpine AS frontend-builder
WORKDIR /app
COPY frontend/package.json frontend/package-lock.json* ./frontend/
WORKDIR /app/frontend
RUN npm ci
WORKDIR /app
COPY frontend ./frontend
WORKDIR /app/frontend
RUN npm run build
# Build stage for backend
FROM golang:1.26-alpine AS backend-builder
WORKDIR /src
RUN apk add --no-cache git ca-certificates
COPY backend/go.mod backend/go.sum* ./backend/
WORKDIR /src/backend
RUN go mod download
WORKDIR /src
COPY backend ./backend
COPY db ./db
WORKDIR /src/backend
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/dash-backend ./cmd/server
# Final stage with supervisord
FROM alpine:3.22
# Install supervisord
RUN apk add --no-cache ca-certificates supervisor
# Create users
RUN adduser -D -H -u 10001 app && \
addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# Setup directories
RUN mkdir -p /app/frontend /data /var/log/supervisor && \
chown -R app:app /data /app && \
chown -R nextjs:nodejs /app/frontend
# Copy backend
COPY --from=backend-builder /out/dash-backend /app/dash-backend
COPY --from=backend-builder /src/db /app/db
# Copy frontend
COPY --from=frontend-builder /app/frontend/public /app/frontend/public
COPY --from=frontend-builder --chown=nextjs:nodejs /app/frontend/.next/standalone /app/frontend/
COPY --from=frontend-builder --chown=nextjs:nodejs /app/frontend/.next/static /app/frontend/.next/static
# Copy supervisord config
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Expose ports
EXPOSE 8080 3000
# Start supervisord
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
+120
View File
@@ -66,6 +66,126 @@ docker compose up --build
Then open http://localhost:3000 Then open http://localhost:3000
### CasaOS Deployment
1. SSH into your CasaOS system
2. Navigate to the AppData directory:
```bash
cd /DATA/AppData/
mkdir dash
cd dash
```
3. Create the docker-compose file:
```bash
nano docker-compose.yml
```
4. Paste the following content:
```yaml
services:
postgres:
image: postgres:16-alpine
container_name: dash-postgres
environment:
POSTGRES_DB: dash
POSTGRES_USER: dash
POSTGRES_PASSWORD: dash
volumes:
- dash-postgres-data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dash -d dash"]
interval: 5s
timeout: 5s
retries: 10
app:
image: ghcr.io/dvorinka/dash:latest
container_name: dash-app
environment:
DATABASE_URL: postgres://dash:dash@postgres:5432/dash?sslmode=disable
DATA_DIR: /data
NEXT_PUBLIC_API_BASE_URL: http://localhost:8080
ports:
- "8080:8080"
- "3000:3000"
volumes:
- dash-backend-data:/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
volumes:
dash-postgres-data:
dash-backend-data:
```
5. Save and exit (Ctrl+O, then Ctrl+X)
6. Start the application:
```bash
docker compose up -d
```
7. Access Dash at http://your-casaos-ip:3000
### Dokploy Deployment
1. In Dokploy, create a new Compose service
2. Select "Docker Compose" as the compose type
3. Paste the following content (replace `your-domain.com` with your actual domain):
```yaml
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: dash
POSTGRES_USER: dash
POSTGRES_PASSWORD: dash
volumes:
- dash-postgres-data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dash -d dash"]
interval: 5s
timeout: 5s
retries: 10
networks:
- dokploy-network
app:
image: ghcr.io/dvorinka/dash:latest
environment:
DATABASE_URL: postgres://dash:dash@postgres:5432/dash?sslmode=disable
DATA_DIR: /data
NEXT_PUBLIC_API_BASE_URL: http://localhost:8080
volumes:
- dash-backend-data:/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
networks:
- dokploy-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.dash.rule=Host(`your-domain.com`)"
- "traefik.http.routers.dash.entrypoints=websecure"
- "traefik.http.routers.dash.tls.certResolver=letsencrypt"
- "traefik.http.services.dash.loadbalancer.server.port=3000"
networks:
dokploy-network:
external: true
volumes:
dash-postgres-data:
dash-backend-data:
```
4. Ensure the DNS A record points to your Dokploy server
5. Deploy the application
6. Wait ~10 seconds for Traefik to generate SSL certificates
7. Access Dash at https://your-domain.com
**Note:** The Dokploy configuration includes Traefik labels for automatic SSL certificate generation and domain routing.
### The Developer Way ### The Developer Way
**Backend:** **Backend:**
+37
View File
@@ -0,0 +1,37 @@
services:
postgres:
image: postgres:16-alpine
container_name: dash-postgres
environment:
POSTGRES_DB: dash
POSTGRES_USER: dash
POSTGRES_PASSWORD: dash
volumes:
- dash-postgres-data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dash -d dash"]
interval: 5s
timeout: 5s
retries: 10
app:
image: ghcr.io/dvorinka/dash:latest
container_name: dash-app
environment:
DATABASE_URL: postgres://dash:dash@postgres:5432/dash?sslmode=disable
DATA_DIR: /data
NEXT_PUBLIC_API_BASE_URL: http://localhost:8080
ports:
- "8080:8080"
- "3000:3000"
volumes:
- dash-backend-data:/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
volumes:
dash-postgres-data:
dash-backend-data:
+46
View File
@@ -0,0 +1,46 @@
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: dash
POSTGRES_USER: dash
POSTGRES_PASSWORD: dash
volumes:
- dash-postgres-data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dash -d dash"]
interval: 5s
timeout: 5s
retries: 10
networks:
- dokploy-network
app:
image: ghcr.io/dvorinka/dash:latest
environment:
DATABASE_URL: postgres://dash:dash@postgres:5432/dash?sslmode=disable
DATA_DIR: /data
NEXT_PUBLIC_API_BASE_URL: http://localhost:8080
volumes:
- dash-backend-data:/data
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
networks:
- dokploy-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.dash.rule=Host(`your-domain.com`)"
- "traefik.http.routers.dash.entrypoints=websecure"
- "traefik.http.routers.dash.tls.certResolver=letsencrypt"
- "traefik.http.services.dash.loadbalancer.server.port=3000"
networks:
dokploy-network:
external: true
volumes:
dash-postgres-data:
dash-backend-data:
+4 -13
View File
@@ -15,34 +15,25 @@ services:
timeout: 5s timeout: 5s
retries: 10 retries: 10
backend: app:
build: build:
context: . context: .
dockerfile: backend/Dockerfile dockerfile: Dockerfile
env_file: env_file:
- .env.example - .env.example
environment: environment:
DATABASE_URL: postgres://dash:dash@postgres:5432/dash?sslmode=disable DATABASE_URL: postgres://dash:dash@postgres:5432/dash?sslmode=disable
DATA_DIR: /data DATA_DIR: /data
NEXT_PUBLIC_API_BASE_URL: http://localhost:8080
ports: ports:
- "8080:8080" - "8080:8080"
- "3000:3000"
volumes: volumes:
- backend-data:/data - backend-data:/data
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
environment:
- NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
ports:
- "3000:3000"
depends_on:
- backend
volumes: volumes:
postgres-data: postgres-data:
backend-data: backend-data:
+29
View File
@@ -0,0 +1,29 @@
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/tmp/supervisord.pid
[program:backend]
command=/app/dash-backend
directory=/app
user=app
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=HTTP_ADDR=":8080",MIGRATIONS_DIR="/app/db/migrations"
[program:frontend]
command=node server.js
directory=/app/frontend
user=nextjs
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=NODE_ENV="production",PORT="3000",HOSTNAME="0.0.0.0",NEXT_PUBLIC_API_BASE_URL="http://localhost:8080"