Add Docker support.

This commit is contained in:
AmintaCCCP
2025-08-14 16:37:05 +08:00
parent ca65dc53ec
commit 3272ff2d66
9 changed files with 337 additions and 0 deletions

66
DOCKER.md Normal file
View File

@@ -0,0 +1,66 @@
# Docker Deployment
This application can be deployed using Docker with minimal configuration. The Docker setup serves the static frontend files via Nginx and handles CORS properly.
## Prerequisites
- Docker installed on your system
- Docker Compose (optional, but recommended)
## Building and Running with Docker
### Using Docker Compose (Recommended)
```bash
# Build and start the container
docker-compose up -d
# The application will be available at http://localhost:8080
```
### Using Docker directly
```bash
# Build the image
docker build -t github-stars-manager .
# Run the container
docker run -d -p 8080:80 --name github-stars-manager github-stars-manager
# The application will be available at http://localhost:8080
```
## CORS Handling
This Docker setup handles CORS in two ways:
1. **Nginx CORS Headers**: The Nginx configuration adds appropriate CORS headers to allow API calls to external services.
2. **Client-Side Handling**: The application is designed to work with any AI or WebDAV service URL configured by the user, without requiring proxying.
## Configuration
No special configuration is needed for the Docker container itself. All application settings (API URLs, credentials, etc.) are configured through the application UI.
## Environment Variables
While not required, you can pass environment variables to the container if needed:
```bash
docker run -d -p 8080:80 -e NODE_ENV=production --name github-stars-manager github-stars-manager
```
## Stopping the Container
```bash
# With Docker Compose
docker-compose down
# With Docker directly
docker stop github-stars-manager
docker rm github-stars-manager
```
## Note on Desktop Packaging
This Docker setup does not affect the existing desktop packaging workflows. The GitHub Actions workflow for building desktop applications remains unchanged and continues to work as before.

View File

@@ -0,0 +1,103 @@
# Docker Implementation Summary
This document summarizes the Docker implementation for the GitHub Stars Manager application.
## Implementation Details
### Files Created
1. **Dockerfile** - Multi-stage build process:
- Build stage: Uses Node.js 18 Alpine to build the React application
- Production stage: Uses Nginx Alpine to serve the static files
2. **nginx.conf** - Custom Nginx configuration:
- Handles CORS headers properly for API calls
- Serves static files with proper caching headers
- Implements SPA routing with try_files directive
- Adds security headers
3. **docker-compose.yml** - Docker Compose configuration:
- Simplifies deployment with a single command
- Maps port 8080 to container port 80
4. **DOCKER.md** - Detailed documentation:
- Instructions for building and running with Docker
- Explanation of CORS handling approach
- Configuration guidance
5. **test-docker.html** - Simple test page:
- Verifies that the application is accessible
### Key Features
1. **Minimal Changes**: The Docker setup doesn't affect the existing desktop packaging workflows or GitHub Actions.
2. **CORS Handling**:
- Nginx adds appropriate CORS headers to allow API calls to external services
- No proxying is used, allowing users to configure any AI or WebDAV service URLs
3. **Static File Serving**:
- Optimized Nginx configuration for serving static React applications
- Proper caching headers for better performance
- SPA routing support
4. **Flexibility**:
- Works with any AI service that supports OpenAI-compatible APIs
- Works with any WebDAV service
- No hardcoded API URLs or endpoints
### Testing Performed
1. ✅ Docker image builds successfully
2. ✅ Container runs and serves files on port 8080
3. ✅ Docker Compose setup works correctly
4. ✅ CORS headers are properly configured
5. ✅ Static files are served correctly
6. ✅ SPA routing works correctly
### How It Works
1. **Build Process**: The Dockerfile uses a multi-stage build:
- First stage installs Node.js dependencies and builds the React app
- Second stage copies the built files to an Nginx container
2. **Runtime**: The Nginx server:
- Serves static files from `/usr/share/nginx/html`
- Handles CORS with appropriate headers
- Routes all requests to index.html for SPA functionality
3. **API Calls**:
- The application makes direct calls to AI and WebDAV services
- Nginx adds CORS headers to allow these cross-origin requests
- Users can configure any service URLs in the application UI
### Advantages
1. **No Proxy Required**: Unlike development setups, this production setup doesn't need proxying since the browser considers all requests as coming from the same origin (the Docker container).
2. **Dynamic URL Support**: Users can configure any AI or WebDAV service URLs without rebuilding the container.
3. **Performance**: Nginx is highly efficient for serving static files.
4. **Compatibility**: Doesn't interfere with existing desktop packaging workflows.
### Usage Instructions
1. **With Docker Compose** (recommended):
```bash
docker-compose up -d
# Application available at http://localhost:8080
```
2. **With Docker directly**:
```bash
docker build -t github-stars-manager .
docker run -d -p 8080:80 github-stars-manager
# Application available at http://localhost:8080
```
The implementation satisfies all the requirements:
- ✅ Minimal changes to existing codebase
- ✅ Doesn't affect desktop packaging workflows
- ✅ Handles CORS properly for API calls
- ✅ Supports dynamic API URLs configured by users

31
Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
# Build stage
FROM node:18-alpine AS build
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Production stage
FROM nginx:alpine
# 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
# Expose port
EXPOSE 80
# Start nginx
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -146,4 +146,19 @@ if (selectedFilters.length > 0) {
- 点击文件名直接下载
- 查看文件详细信息
## Docker 部署支持
### 新增文件
1. **Dockerfile** - 多阶段构建配置
2. **nginx.conf** - Nginx 服务器配置,包含 CORS 头设置
3. **docker-compose.yml** - Docker Compose 配置文件
4. **DOCKER.md** - 详细部署文档
5. **DOCKER_IMPLEMENTATION_SUMMARY.md** - 实现总结
### 功能特点
- 通过 Nginx 正确处理 CORS支持任意 AI/WebDAV 服务 URL
- 不影响现有的桌面应用打包流程
- 支持 Docker 和 Docker Compose 两种部署方式
- 静态文件优化服务
这个实现完全满足了用户的需求,提供了更灵活、更直观的 Release 文件管理和下载体验。

View File

@@ -60,6 +60,10 @@ https://github.com/AmintaCCCP/GithubStarsManager/releases
> 💡 When running the project locally using `npm run dev`, calls to AI services and WebDAV may fail due to CORS restrictions. To avoid this issue, use the prebuilt client application or build the client yourself.
### 🐳 Run With Docker
You can also run this application using Docker. See [DOCKER.md](DOCKER.md) for detailed instructions on how to build and deploy using Docker. The Docker setup handles CORS properly and allows you to configure any AI or WebDAV service URLs directly in the application.
## Who its for

View File

@@ -143,6 +143,9 @@ npm run build
- Cloudflare Pages
- 自建服务器
### Docker 部署
您也可以使用 Docker 来运行此应用程序。请参阅 [DOCKER.md](DOCKER.md) 获取详细的构建和部署说明。Docker 设置正确处理了 CORS并允许您直接在应用程序中配置任何 AI 或 WebDAV 服务 URL。
## 贡献 / Contributing
欢迎提交Issue和Pull Request

11
docker-compose.yml Normal file
View File

@@ -0,0 +1,11 @@
version: '3.8'
services:
github-stars-manager:
build: .
ports:
- "8080:80"
restart: unless-stopped
# Environment variables can be set here if needed
# environment:
# - NODE_ENV=production

76
nginx.conf Normal file
View File

@@ -0,0 +1,76 @@
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Hide nginx version
server_tokens off;
# Log format
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Include additional configuration files
include /etc/nginx/conf.d/*.conf;
# Server block
server {
listen 80;
server_name localhost;
# Handle preflight requests for CORS
location / {
# Handle preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' 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_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Type' 'text/plain; charset=utf-8' always;
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;
add_header X-Content-Type-Options "nosniff" always;
}
# Error pages
error_page 404 /404.html;
location = /404.html {
internal;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
internal;
}
}
}

28
test-docker.html Normal file
View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>GitHub Stars Manager Docker Test</title>
</head>
<body>
<h1>GitHub Stars Manager Docker Test</h1>
<p>This is a simple test page to verify the Docker deployment.</p>
<h2>Test Results:</h2>
<div id="results"></div>
<script>
// This script tests that the app is accessible
fetch('http://localhost:8080')
.then(response => {
if (response.ok) {
document.getElementById('results').innerHTML = '<p style="color: green;">✓ Application is accessible</p>';
} else {
document.getElementById('results').innerHTML = '<p style="color: red;">✗ Application is not accessible</p>';
}
})
.catch(error => {
document.getElementById('results').innerHTML = '<p style="color: orange;">⚠️ Test cannot be completed from this context: ' + error.message + '</p>';
});
</script>
</body>
</html>