diff --git a/.env.example b/.env.example index e4a1e84..4b8d562 100644 --- a/.env.example +++ b/.env.example @@ -1,9 +1,14 @@ -# Server -JWT_SECRET=change-me-to-a-random-secret +# Mot de passe Gitea (optionnel — si absent, le script le demande interactivement) +GITEA_PASSWORD=ton-mot-de-passe -# Token for the local agent (generate with: uuidgen) +# Serveur +JWT_SECRET=change-me-to-a-random-secret +ADMIN_USER=admin +ADMIN_PASSWORD=change-me + +# Token pour l'agent local (même VM que le serveur) LOCAL_AGENT_TOKEN=change-me-to-a-random-token -# Remote agents only (docker-compose.agent.yml) -CONTAINARR_SERVER_URL=http://:9090 -CONTAINARR_AGENT_TOKEN= +# Agents distants uniquement (docker-compose.agent.yml) +CONTAINARR_SERVER_URL=http://:9090 +CONTAINARR_AGENT_TOKEN= diff --git a/.gitignore b/.gitignore index 76a4e7e..0f67a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ web/.env.* # ── Docker ──────────────────────────────────────────────────────────────────── *.tar +# ── Scripts locaux ──────────────────────────────────────────────────────────── +push.sh + # ── Données & secrets ───────────────────────────────────────────────────────── *.db *.db-wal diff --git a/docker-compose.agent.yml b/docker-compose.agent.yml index d5bda0a..b75392d 100644 --- a/docker-compose.agent.yml +++ b/docker-compose.agent.yml @@ -1,9 +1,6 @@ services: agent: - image: ghcr.io/containarr/agent:latest # or build locally - # build: - # context: . - # dockerfile: agent/Dockerfile + image: gitea.anthonybouteiller.ovh/blomios/containarr-agent:latest restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock:ro diff --git a/docker-compose.server.yml b/docker-compose.server.yml index 91ba4c2..7ea71ca 100644 --- a/docker-compose.server.yml +++ b/docker-compose.server.yml @@ -1,8 +1,6 @@ services: server: - build: - context: ./server - image: containarr-server:latest + image: gitea.anthonybouteiller.ovh/blomios/containarr-server:latest restart: unless-stopped ports: - "8080:8080" # HTTP + WebSocket (PWA) @@ -18,12 +16,8 @@ services: ADMIN_PASSWORD: "${ADMIN_PASSWORD}" BOOTSTRAP_TOKENS: "local:${LOCAL_AGENT_TOKEN}" - # Agent for the local VM (same host as the server). agent: - build: - context: . - dockerfile: agent/Dockerfile - image: containarr-agent:latest + image: gitea.anthonybouteiller.ovh/blomios/containarr-agent:latest restart: unless-stopped depends_on: - server diff --git a/server/Dockerfile b/server/Dockerfile index 8577b04..35a2cbc 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,20 +1,33 @@ -FROM golang:1.23-alpine AS builder +# Context: project root +# docker build -f server/Dockerfile -t containarr-server . +# ── Stage 1 : build SvelteKit ───────────────────────────────────────────────── +FROM node:20-alpine AS web-builder +WORKDIR /web +COPY web/package*.json ./ +RUN npm ci +COPY web/ ./ +RUN npm run build +# Output: /web/build/ + +# ── Stage 2 : build Go server ───────────────────────────────────────────────── +FROM golang:1.23-alpine AS go-builder RUN apk add --no-cache gcc musl-dev - WORKDIR /src -COPY go.mod go.sum ./ -COPY . . -RUN go mod tidy && CGO_ENABLED=1 GOOS=linux go build -ldflags="-s -w" -o /bin/containarr-server ./cmd/server +COPY server/go.mod server/go.sum ./ +RUN go mod download +COPY server/ ./ +RUN CGO_ENABLED=1 GOOS=linux go build -ldflags="-s -w" -o /bin/containarr-server ./cmd/server -# ── Runtime ─────────────────────────────────────────────────────────────────── +# ── Stage 3 : image finale ──────────────────────────────────────────────────── FROM alpine:3.20 - RUN apk add --no-cache ca-certificates tzdata -COPY --from=builder /bin/containarr-server /usr/local/bin/containarr-server +WORKDIR /app +COPY --from=go-builder /bin/containarr-server ./containarr-server +COPY --from=web-builder /web/build ./web/build VOLUME ["/data"] EXPOSE 8080 9090 -ENTRYPOINT ["containarr-server"] +ENTRYPOINT ["/app/containarr-server"] diff --git a/server/internal/api/router.go b/server/internal/api/router.go index 5600ef1..e4af86c 100644 --- a/server/internal/api/router.go +++ b/server/internal/api/router.go @@ -2,11 +2,33 @@ package api import ( "net/http" + "os" + "path/filepath" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) +const webBuildDir = "./web/build" + +// spaHandler serves static files from dir and falls back to index.html for +// any path that does not match an existing file on disk. This supports +// SvelteKit (adapter-static, fallback: "index.html") running as a SPA. +func spaHandler(dir string) http.HandlerFunc { + fs := http.FileServer(http.Dir(dir)) + return func(w http.ResponseWriter, r *http.Request) { + // Resolve the requested path inside the build directory. + abs := filepath.Join(dir, filepath.Clean("/"+r.URL.Path)) + if info, err := os.Stat(abs); err == nil && !info.IsDir() { + // File exists — serve it normally (assets, icons, _app/*, …). + fs.ServeHTTP(w, r) + return + } + // No matching file found: serve the SPA entry point. + http.ServeFile(w, r, filepath.Join(dir, "index.html")) + } +} + func NewRouter(h *Handler) http.Handler { r := chi.NewRouter() r.Use(middleware.Logger) @@ -29,7 +51,7 @@ func NewRouter(h *Handler) http.Handler { }) }) - r.Handle("/*", http.FileServer(http.Dir("./web/dist"))) + r.Handle("/*", spaHandler(webBuildDir)) return r }