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.*
|
||||||
!.env.example
|
!.env.example
|
||||||
scripts/env/dev.env
|
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
|
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
|
## Layout
|
||||||
|
|
||||||
- `backend/cmd/warpbox` - main application entry point.
|
- `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}", a.DownloadFile)
|
||||||
mux.HandleFunc("GET /d/{boxID}/f/{fileID}/download", a.DownloadFileContent)
|
mux.HandleFunc("GET /d/{boxID}/f/{fileID}/download", a.DownloadFileContent)
|
||||||
mux.HandleFunc("GET /d/{boxID}/thumb/{fileID}", a.Thumbnail)
|
mux.HandleFunc("GET /d/{boxID}/thumb/{fileID}", a.Thumbnail)
|
||||||
|
mux.HandleFunc("GET /health", a.Health)
|
||||||
mux.HandleFunc("GET /healthz", a.Health)
|
mux.HandleFunc("GET /healthz", a.Health)
|
||||||
mux.HandleFunc("GET /api/v1/health", a.Health)
|
mux.HandleFunc("GET /api/v1/health", a.Health)
|
||||||
mux.HandleFunc("GET /api/v1/sharex/warpbox-anonymous.sxcu", a.ShareXAnonymousConfig)
|
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