feat: add Docker support and Gitea publish workflow
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m38s
All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m38s
- Add a multi-stage Dockerfile for building and running the Go backend - Add .dockerignore to optimize the Docker build context - Create a Gitea Actions workflow to build and publish Docker images on tag push - Register a new `/health` endpoint for container healthchecks - Update README.md with Docker and Podman deployment instructions - Ignore local `docker-compose.yml` in .gitignore
This commit is contained in:
23
.dockerignore
Normal file
23
.dockerignore
Normal file
@@ -0,0 +1,23 @@
|
||||
.git
|
||||
.gitea
|
||||
.github
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
data
|
||||
backend/warpbox
|
||||
warpbox
|
||||
|
||||
.env
|
||||
scripts/env/*.env
|
||||
!scripts/env/*.env.example
|
||||
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
.DS_Store
|
||||
|
||||
docs/Mock-Up/Mockup Magic/node_modules
|
||||
docs/Mock-Up/Mockup Magic/.tanstack
|
||||
docs/Mock-Up/Mockup Magic/dist
|
||||
docs/Mock-Up/Mockup Magic/.wrangler
|
||||
46
.gitea/workflows/publish.yml
Normal file
46
.gitea/workflows/publish.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Build and Publish Docker Image
|
||||
run-name: Publishing ${{ gitea.ref_name }}
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: backend/go.mod
|
||||
cache: false
|
||||
|
||||
- name: Run Tests
|
||||
run: cd backend && go test ./...
|
||||
|
||||
- name: Install Docker
|
||||
run: curl -fsSL https://get.docker.com | sh
|
||||
|
||||
- name: Build Docker Image
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg APP_VERSION=${{ gitea.ref_name }} \
|
||||
-t tea.chunkbyte.com/kato/warpbox-dev:${{ gitea.ref_name }} \
|
||||
-t tea.chunkbyte.com/kato/warpbox-dev:latest \
|
||||
.
|
||||
|
||||
- name: Login to Gitea Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: tea.chunkbyte.com
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Push Docker Image
|
||||
run: |
|
||||
docker push tea.chunkbyte.com/kato/warpbox-dev:${{ gitea.ref_name }}
|
||||
docker push tea.chunkbyte.com/kato/warpbox-dev:latest
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ backend/static/uploads/*
|
||||
.env.*
|
||||
!.env.example
|
||||
scripts/env/dev.env
|
||||
docker-compose.yml
|
||||
|
||||
40
Dockerfile
Normal file
40
Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM golang:1.26-alpine AS builder
|
||||
|
||||
WORKDIR /src/backend
|
||||
|
||||
COPY backend/go.mod backend/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY backend/ ./
|
||||
|
||||
ARG APP_VERSION=dev
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||
-trimpath \
|
||||
-ldflags="-s -w -X main.version=${APP_VERSION}" \
|
||||
-o /out/warpbox \
|
||||
./cmd/warpbox
|
||||
|
||||
FROM alpine:3.22
|
||||
|
||||
RUN apk add --no-cache ca-certificates ffmpeg wget
|
||||
|
||||
ENV WARPBOX_ADDR=:8080 \
|
||||
WARPBOX_DATA_DIR=/data \
|
||||
WARPBOX_STATIC_DIR=/app/static \
|
||||
WARPBOX_TEMPLATE_DIR=/app/templates
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /out/warpbox /usr/local/bin/warpbox
|
||||
COPY backend/static /app/static
|
||||
COPY backend/templates /app/templates
|
||||
|
||||
RUN mkdir -p /data
|
||||
|
||||
EXPOSE 8080
|
||||
VOLUME ["/data"]
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||
CMD wget -qO- http://127.0.0.1:8080/health >/dev/null || exit 1
|
||||
|
||||
ENTRYPOINT ["warpbox"]
|
||||
19
README.md
19
README.md
@@ -29,6 +29,25 @@ cd backend
|
||||
go run ./cmd/warpbox
|
||||
```
|
||||
|
||||
## Docker / Podman
|
||||
|
||||
Copy the example environment file and adjust values such as `WARPBOX_BASE_URL` and
|
||||
`WARPBOX_ADMIN_TOKEN` before running the container:
|
||||
|
||||
Copy the example [docker-compose.example.yml](./docker-compose.example.yml) to [docker-compose.yml](./docker-compose.yml), modify as need-be
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
docker compose -f docker-compose.yml up --build
|
||||
```
|
||||
|
||||
The compose example also works with Podman compatible compose tools. Its data volume uses
|
||||
`./data:/data:Z` for SELinux relabeling, and the container overrides runtime paths to use
|
||||
`/data`, `/app/static`, and `/app/templates`.
|
||||
|
||||
The image exposes `/health`, `/healthz`, and `/api/v1/health`. Docker and compose healthchecks
|
||||
use `/health`.
|
||||
|
||||
## Layout
|
||||
|
||||
- `backend/cmd/warpbox` - main application entry point.
|
||||
|
||||
@@ -44,6 +44,7 @@ func (a *App) RegisterRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("GET /d/{boxID}/f/{fileID}", a.DownloadFile)
|
||||
mux.HandleFunc("GET /d/{boxID}/f/{fileID}/download", a.DownloadFileContent)
|
||||
mux.HandleFunc("GET /d/{boxID}/thumb/{fileID}", a.Thumbnail)
|
||||
mux.HandleFunc("GET /health", a.Health)
|
||||
mux.HandleFunc("GET /healthz", a.Health)
|
||||
mux.HandleFunc("GET /api/v1/health", a.Health)
|
||||
mux.HandleFunc("GET /api/v1/sharex/warpbox-anonymous.sxcu", a.ShareXAnonymousConfig)
|
||||
|
||||
28
backend/libs/handlers/health_test.go
Normal file
28
backend/libs/handlers/health_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHealthRoutes(t *testing.T) {
|
||||
app, cleanup := newTestApp(t)
|
||||
defer cleanup()
|
||||
|
||||
mux := http.NewServeMux()
|
||||
app.RegisterRoutes(mux)
|
||||
|
||||
for _, path := range []string{"/health", "/healthz", "/api/v1/health"} {
|
||||
t.Run(path, func(t *testing.T) {
|
||||
request := httptest.NewRequest(http.MethodGet, path, nil)
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
mux.ServeHTTP(response, request)
|
||||
|
||||
if response.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, body = %s", response.Code, response.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
24
docker-compose.example.yml
Normal file
24
docker-compose.example.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
services:
|
||||
warpbox-dev:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: warpbox-dev:local
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
WARPBOX_ADDR: ":8080"
|
||||
WARPBOX_DATA_DIR: /data
|
||||
WARPBOX_STATIC_DIR: /app/static
|
||||
WARPBOX_TEMPLATE_DIR: /app/templates
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./data:/data:Z
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/health >/dev/null || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 3s
|
||||
start_period: 10s
|
||||
retries: 3
|
||||
Reference in New Issue
Block a user