Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.git
.github
.claude
.vscode
.sisyphus
.omo
.writing
server
node_modules
dist
build
electron
upload
versions
LandingPage
cloudflare-worker
assets
templates
*.md
.DS_Store
63 changes: 63 additions & 0 deletions .github/workflows/docker-publish-frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Publish Frontend Docker Image to GHCR

on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/github-stars-manager-frontend

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# branch push → "latest"
type=raw,value=latest,enable={{is_default_branch}}
# tag push → "v1.2.3", "1.2.3", "1.2", "1"
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# every build → sha-abc1234
type=sha,prefix=sha-
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Build and push Docker image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
47 changes: 37 additions & 10 deletions DOCKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,21 @@ docker-compose up -d
> ```
> Use a [Personal Access Token](https://github.com/settings/tokens) (with `read:packages` scope) as the password.

Available image tags:
Available image tags (both images share the same tagging scheme):
- `latest` — latest build from the `main` branch
- `v0.6.2`, `0.6.2` — specific version tags
- `0.6.2`, `0.6`, `0` — specific version tags (semver, `v` prefix stripped)
- `sha-abc1234` — specific commit builds

To pin a specific version in `docker-compose.yml`, set `BACKEND_IMAGE_TAG` in your `.env` file:
Published images:
- Backend: `ghcr.io/amintacccp/github-stars-manager-server`
- Frontend: `ghcr.io/amintacccp/github-stars-manager-frontend`

To pin specific versions in `docker-compose.yml`, set `BACKEND_IMAGE_TAG` and/or
`FRONTEND_IMAGE_TAG` in your `.env` file:

```bash
BACKEND_IMAGE_TAG=v0.6.2
BACKEND_IMAGE_TAG=0.6.2
FRONTEND_IMAGE_TAG=0.6.2
```

## Backend Server (docker run)
Expand Down Expand Up @@ -84,12 +90,14 @@ docker run -d \
docker-compose up -d
```

To customize secrets, create a `.env` file in the project root:
To customize secrets and image versions, create a `.env` file in the project root:

```bash
API_SECRET=my-strong-secret
ENCRYPTION_KEY=my-encryption-key
BACKEND_IMAGE_TAG=v0.6.2 # pin backend image version (default: latest)
BACKEND_IMAGE_TAG=0.6.2 # pin backend image version (default: latest)
FRONTEND_IMAGE_TAG=0.6.2 # pin frontend image version (default: latest)
# BACKEND_HOST=backend:3000 # target for the frontend's /api proxy (default: backend:3000)
```

Then `docker-compose up -d` reads them automatically.
Expand Down Expand Up @@ -122,16 +130,35 @@ Then run `docker-compose up -d --build`. The override file takes precedence auto

### Using Docker directly (frontend only)

The pre-built frontend image is published to GHCR — no local build required:

```bash
# Build the image
docker build -t github-stars-manager .
# Pull the published image
docker pull ghcr.io/amintacccp/github-stars-manager-frontend:latest

# Run the container
docker run -d -p 8080:80 --name github-stars-manager github-stars-manager
# Run the container (point /api proxy at your backend)
docker run -d -p 8080:80 \
-e BACKEND_HOST=host.docker.internal:3000 \
--name github-stars-manager \
ghcr.io/amintacccp/github-stars-manager-frontend:latest

# The application will be available at http://localhost:8080
```

> `BACKEND_HOST` sets the upstream the frontend proxies `/api/` to. In Docker Compose
> it defaults to `backend:3000`. When running standalone, point it at your backend's
> reachable address (e.g. `host.docker.internal:3000` on Docker Desktop, or the backend
> container's IP/host on a shared network).

To build the image locally instead (uses the repository `Dockerfile`):

```bash
docker build -t github-stars-manager .
docker run -d -p 8080:80 \
-e BACKEND_HOST=host.docker.internal:3000 \
--name github-stars-manager github-stars-manager
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## CORS Handling

This Docker setup handles CORS in two ways:
Expand Down
9 changes: 5 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ RUN rm -f /etc/nginx/conf.d/default.conf
# Copy built files from build stage
COPY --from=build /app/dist /usr/share/nginx/html

# Copy custom nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf
# Copy custom nginx configuration template (rendered at startup with BACKEND_HOST)
COPY nginx.conf.template /etc/nginx/nginx.conf.template

# Expose port
EXPOSE 80

# Start nginx
CMD ["nginx", "-g", "daemon off;"]
# Render the nginx config (substituting BACKEND_HOST, defaulting to backend:3000)
# and start nginx
CMD ["sh", "-c", "export BACKEND_HOST=${BACKEND_HOST:-backend:3000}; envsubst '${BACKEND_HOST}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && nginx -g 'daemon off;'"]
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,11 @@ https://github.com/AmintaCCCP/GithubStarsManager/releases

### 🐳 Run With Docker

Pre-built backend image is available on GHCR — no local build required:
Pre-built backend **and frontend** images are available on GHCR — no local build required:

```bash
docker pull ghcr.io/amintacccp/github-stars-manager-server:latest
docker pull ghcr.io/amintacccp/github-stars-manager-frontend:latest
docker-compose up -d
```

Expand All @@ -240,7 +241,8 @@ To customize, create a `.env` file:
```bash
API_SECRET=your-secret
ENCRYPTION_KEY=your-key
BACKEND_IMAGE_TAG=v0.6.2 # pin a specific version (default: latest)
BACKEND_IMAGE_TAG=0.6.2 # pin backend image version (default: latest)
FRONTEND_IMAGE_TAG=0.6.2 # pin frontend image version (default: latest)
```

#### Backend only (docker run)
Expand Down
6 changes: 4 additions & 2 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,11 @@ npm run build

### Docker 部署

GHCR 上有预构建的后端镜像,无需本地构建:
GHCR 上提供预构建的**后端和前端**镜像,无需本地构建:

```bash
docker pull ghcr.io/amintacccp/github-stars-manager-server:latest
docker pull ghcr.io/amintacccp/github-stars-manager-frontend:latest
docker-compose up -d
```

Expand All @@ -357,7 +358,8 @@ docker-compose up -d
```bash
API_SECRET=your-secret
ENCRYPTION_KEY=your-key
BACKEND_IMAGE_TAG=v0.6.2 # 固定版本(默认:latest)
BACKEND_IMAGE_TAG=0.6.2 # 固定后端版本(默认:latest)
FRONTEND_IMAGE_TAG=0.6.2 # 固定前端版本(默认:latest)
```

#### 仅后端(docker run)
Expand Down
6 changes: 5 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ version: '3.8'

services:
frontend:
build: .
image: ghcr.io/amintacccp/github-stars-manager-frontend:${FRONTEND_IMAGE_TAG:-latest}
# Uncomment below (and comment out 'image') to build locally instead:
# build: .
ports:
- "8080:80"
depends_on:
- backend
environment:
- BACKEND_HOST=${BACKEND_HOST:-backend:3000}
restart: unless-stopped

backend:
Expand Down
15 changes: 6 additions & 9 deletions nginx.conf → nginx.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ events {
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
resolver 127.0.0.11 ipv6=off valid=30s;

# Hide nginx version
server_tokens off;
Expand All @@ -31,10 +30,9 @@ http {
server {
listen 80;
server_name localhost;
# Backend API proxy
# Backend API proxy (configurable via BACKEND_HOST, default: backend:3000)
location /api/ {
set $backend_upstream backend:3000;
proxy_pass http://$backend_upstream;
proxy_pass http://${BACKEND_HOST};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
Expand All @@ -60,19 +58,18 @@ http {
add_header 'Content-Length' 0 always;
return 204;
}

root /usr/share/nginx/html;
index index.html index.htm;

# Try to serve file, if not found, serve index.html (for SPA routing)
try_files $uri $uri/ /index.html;

# Add CORS headers for all responses
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;

# Add security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
Expand Down
Loading