refactor(docker): build and ship a single API + UI image

Collapse the separate backend (Node) and frontend (nginx) images into
one image where the Express backend serves the built React app in
addition to the API and game content, so deployment is a single
container and one origin.

- Add a root Dockerfile with frontend-builder + backend-builder stages
  producing one runtime image; remove backend/ and frontend/ Dockerfiles,
  the nginx config, and the frontend entrypoint
- Serve the frontend dist and SPA fallback from Express (config.serveFrontend
  / FRONTEND_DIST_PATH), before auth/maintenance so the shell always loads and
  before the API 404 so client routes resolve to index.html
- Port the SPA-oriented CSP from nginx into Helmet, gated on serveFrontend;
  keep the strict API-only policy otherwise
- Reduce both compose files to a single flashpoint-web service on WEB_PORT
  -> 3100; drop API_PORT, BACKEND_HOST, BACKEND_PORT
- Build one image in the release workflow instead of a two-service matrix
- Update .env.example, README, workflow README, and env var docs

Also add .gitattributes (*.sh eol=lf) and normalize the entrypoint line
endings — without it, Windows checkouts bake CRLF into the image and the
shebang fails with "no such file or directory".
This commit is contained in:
Darkraise
2026-08-11 16:02:06 +07:00
parent a41eac0101
commit 3ba60aedf9
16 changed files with 289 additions and 592 deletions
+21 -42
View File
@@ -6,18 +6,17 @@ This directory contains automated workflows for the Flashpoint Web project.
### 1. Docker Build and Push (`docker-build-push.yml`)
Builds and pushes Docker images for all three services to container registries.
Builds and pushes the single Docker image to the container registry.
#### Triggers
- **Version tags** (`v*.*.*`): Builds and pushes images with version tags and `latest` tag
- **Version tags** (`v*.*.*`): Builds and pushes the image with version tags and `latest` tag
- **Manual dispatch**: Can be triggered manually from GitHub Actions tab
#### Services Built
#### Image Built
- `flashpoint-backend` - REST API server
- `flashpoint-frontend` - React web UI (Nginx)
- `flashpoint-game-service` - Game content proxy and ZIP server
- `flashpoint-web` - Single image serving both the REST API (including game
content) and the React web UI
#### Container Registry
@@ -43,11 +42,9 @@ The workflow pushes images to **Docker Hub**.
- `DOCKERHUB_USERNAME`: Your Docker Hub username
- `DOCKERHUB_TOKEN`: The access token from step 2
4. **Images will be pushed to**:
4. **Image will be pushed to**:
```
docker.io/darkraise/flashpoint-backend:latest
docker.io/darkraise/flashpoint-frontend:latest
docker.io/darkraise/flashpoint-game-service:latest
docker.io/darkraise/flashpoint-web:latest
```
#### Image Tags
@@ -98,51 +95,34 @@ The workflow uses GitHub Actions cache to speed up builds:
#### Usage Examples
##### Pull and Run Images
##### Pull and Run the Image
```bash
# Pull latest images
docker pull darkraise/flashpoint-backend:latest
docker pull darkraise/flashpoint-frontend:latest
docker pull darkraise/flashpoint-game-service:latest
# Pull the latest image
docker pull darkraise/flashpoint-web:latest
# Or use a specific version
docker pull darkraise/flashpoint-backend:1.0.0
docker pull darkraise/flashpoint-web:1.0.0
```
##### Use in Docker Compose
Update your `docker-compose.yml` to use pre-built images:
Update your `docker-compose.yml` to use the pre-built image:
```yaml
version: '3.8'
services:
backend:
image: darkraise/flashpoint-backend:latest
flashpoint-web:
image: darkraise/flashpoint-web:latest
# Remove build section
ports:
- "3100:3100"
# ... rest of config
frontend:
image: darkraise/flashpoint-frontend:latest
ports:
- "80:8080"
# ... rest of config
game-service:
image: darkraise/flashpoint-game-service:latest
ports:
- "22500:22500"
- "22501:22501"
- "80:3100"
# ... rest of config
```
Then simply run:
```bash
docker-compose pull # Pull latest images
docker-compose up -d # Start services
docker compose pull # Pull the latest image
docker compose up -d # Start the service
```
#### Making Images Public
@@ -150,7 +130,7 @@ docker-compose up -d # Start services
By default, Docker Hub images are private. To make them public:
1. Go to https://hub.docker.com/repositories
2. Click on the repository (e.g., `flashpoint-backend`)
2. Click on the repository (e.g., `flashpoint-web`)
3. Click "Settings"
4. Change visibility to "Public"
@@ -179,10 +159,9 @@ docker login docker.io
#### Performance
Typical build times (optimized for amd64 only):
- First build: 3-5 minutes per service
- Subsequent builds (with cache): 1-2 minutes per service
- Parallel execution: All 3 services build simultaneously
- Total workflow time: ~6-10 minutes (down from 12+ minutes)
- First build: 3-5 minutes
- Subsequent builds (with cache): 1-2 minutes
- Frontend and backend build stages run within a single image build
**Optimizations applied:**
- Single platform (amd64) instead of multi-platform
+14 -27
View File
@@ -13,16 +13,6 @@ jobs:
build-and-push:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
service:
- name: backend
context: .
dockerfile: ./backend/Dockerfile
- name: frontend
context: .
dockerfile: ./frontend/Dockerfile
permissions:
contents: read
@@ -52,7 +42,7 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY_DOCKERHUB }}/${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-${{ matrix.service.name }}
images: ${{ env.REGISTRY_DOCKERHUB }}/${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-web
tags: |
# Tag with full version (v1.0.0 -> 1.0.0)
type=semver,pattern={{version}}
@@ -63,16 +53,16 @@ jobs:
# Latest tag
type=raw,value=latest
- name: Build and push Docker images
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ matrix.service.context }}
file: ${{ matrix.service.dockerfile }}
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.service.name }}
cache-to: type=gha,scope=${{ matrix.service.name }},mode=max
cache-from: type=gha,scope=flashpoint-web
cache-to: type=gha,scope=flashpoint-web,mode=max
platforms: linux/amd64
build-args: |
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
@@ -90,17 +80,15 @@ jobs:
run: |
echo "## Docker Build Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Images Built:" >> $GITHUB_STEP_SUMMARY
echo "- \`flashpoint-backend\`" >> $GITHUB_STEP_SUMMARY
echo "- \`flashpoint-frontend\`" >> $GITHUB_STEP_SUMMARY
echo "### Image Built:" >> $GITHUB_STEP_SUMMARY
echo "- \`flashpoint-web\` (API + UI)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Registry:" >> $GITHUB_STEP_SUMMARY
echo "- Docker Hub: \`${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-*\`" >> $GITHUB_STEP_SUMMARY
echo "- Docker Hub: \`${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-web\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Pull Commands:" >> $GITHUB_STEP_SUMMARY
echo "### Pull Command:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-backend:latest" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-frontend:latest" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-web:latest" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
create-release:
@@ -127,13 +115,12 @@ jobs:
# Get the previous tag
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
echo "## Docker Images" >> release_notes.md
echo "## Docker Image" >> release_notes.md
echo "" >> release_notes.md
echo "Pull the images from Docker Hub:" >> release_notes.md
echo "Pull the image from Docker Hub:" >> release_notes.md
echo "" >> release_notes.md
echo "\`\`\`bash" >> release_notes.md
echo "docker pull ${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-backend:${{ steps.version.outputs.version }}" >> release_notes.md
echo "docker pull ${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-frontend:${{ steps.version.outputs.version }}" >> release_notes.md
echo "docker pull ${{ secrets.DOCKERHUB_USERNAME }}/flashpoint-web:${{ steps.version.outputs.version }}" >> release_notes.md
echo "\`\`\`" >> release_notes.md
echo "" >> release_notes.md