Image in der CI bauen statt zur Laufzeit, Site ins Image backen
Some checks failed
Image bauen und in die Registry pushen / build (push) Has been cancelled
Some checks failed
Image bauen und in die Registry pushen / build (push) Has been cancelled
Bisher baute der Server das Image selbst und der Container holte sich Inhalte per git pull ueber deploy.php. Das war seit jeher kaputt: git verweigerte wegen "dubious ownership" die Arbeit, die &&-Kette brach ab, hugo lief nie. Live war stets der Stand des letzten Containerstarts. Statt das zu flicken faellt der Mechanismus jetzt weg. Das Dockerfile ist zweistufig: Hugo baut die Seite im Builder, das Laufzeit-Image enthaelt nur nginx und fertiges HTML. Kein PHP, kein git, kein Hugo mehr zur Laufzeit - 49 MB statt eines Debian-Images mit vier Werkzeugketten. Deployen heisst damit: neues Image ziehen, Container neu starten. Entfernt: deploy.php, entrypoint.sh und .htaccess (Apache-Rest aus der Kirby-Zeit, unter nginx wirkungslos). Der Ordner kirby/ heisst jetzt docker/, weil dort nie Kirby lag. docker-compose.yml zieht das Image aus der Registry. Das Volume-Mount auf /var/www/html ist weg - es haette die ins Image gebackene Seite verdeckt. Lokal geprueft: Build laeuft durch, Container liefert alle Seiten und Assets mit HTTP 200 aus, Intro-Text kommt aus der Markdown-Datei, alle sieben Lampenbilder sind enthalten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
46
.gitea/workflows/build.yml
Normal file
46
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: Image bauen und in die Registry pushen
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: gitea.mindboost.team
|
||||||
|
IMAGE: gitea.mindboost.team/rorapp/robbis.space
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Repository auschecken
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# themes/gokarna ist ein Submodule und wird fuer den Hugo-Build
|
||||||
|
# zwingend gebraucht. Ohne dies bricht der Dockerfile-Check ab.
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Buildx einrichten
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: An der Registry anmelden
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ secrets.REGISTRY_USER }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Bauen und pushen
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: docker/Dockerfile
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
${{ env.IMAGE }}:latest
|
||||||
|
${{ env.IMAGE }}:${{ gitea.sha }}
|
||||||
|
cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache
|
||||||
|
cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max
|
||||||
67
.htaccess
67
.htaccess
@@ -1,67 +0,0 @@
|
|||||||
# Kirby .htaccess
|
|
||||||
# revision 2023-07-22
|
|
||||||
|
|
||||||
# rewrite rules
|
|
||||||
<IfModule mod_rewrite.c>
|
|
||||||
|
|
||||||
# enable awesome urls. i.e.:
|
|
||||||
# http://yourdomain.com/about-us/team
|
|
||||||
RewriteEngine on
|
|
||||||
|
|
||||||
# make sure to set the RewriteBase correctly
|
|
||||||
# if you are running the site in a subfolder;
|
|
||||||
# otherwise links or the entire site will break.
|
|
||||||
#
|
|
||||||
# If your homepage is http://yourdomain.com/mysite,
|
|
||||||
# set the RewriteBase to:
|
|
||||||
#
|
|
||||||
# RewriteBase /mysite
|
|
||||||
|
|
||||||
# In some environments it's necessary to
|
|
||||||
# set the RewriteBase to:
|
|
||||||
#
|
|
||||||
# RewriteBase /
|
|
||||||
|
|
||||||
# block files and folders beginning with a dot, such as .git
|
|
||||||
# except for the .well-known folder, which is used for Let's Encrypt and security.txt
|
|
||||||
RewriteRule (^|/)\.(?!well-known\/) index.php [L]
|
|
||||||
|
|
||||||
# block all files in the content folder from being accessed directly
|
|
||||||
RewriteRule ^content/(.*) index.php [L]
|
|
||||||
|
|
||||||
# block all files in the site folder from being accessed directly
|
|
||||||
RewriteRule ^site/(.*) index.php [L]
|
|
||||||
|
|
||||||
# block direct access to Kirby and the Panel sources
|
|
||||||
RewriteRule ^kirby/(.*) index.php [L]
|
|
||||||
|
|
||||||
# make site links work
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
RewriteRule ^(.*) index.php [L]
|
|
||||||
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
# pass the Authorization header to PHP
|
|
||||||
SetEnvIf Authorization "(.+)" HTTP_AUTHORIZATION=$1
|
|
||||||
|
|
||||||
# compress text file responses
|
|
||||||
<IfModule mod_deflate.c>
|
|
||||||
AddOutputFilterByType DEFLATE text/plain
|
|
||||||
AddOutputFilterByType DEFLATE text/html
|
|
||||||
AddOutputFilterByType DEFLATE text/css
|
|
||||||
AddOutputFilterByType DEFLATE text/javascript
|
|
||||||
AddOutputFilterByType DEFLATE application/json
|
|
||||||
AddOutputFilterByType DEFLATE application/javascript
|
|
||||||
AddOutputFilterByType DEFLATE application/x-javascript
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
# set security headers in all responses
|
|
||||||
<IfModule mod_headers.c>
|
|
||||||
|
|
||||||
# serve files as plain text if the actual content type is not known
|
|
||||||
# (hardens against attacks from malicious file uploads)
|
|
||||||
Header set Content-Type "text/plain" "expr=-z %{CONTENT_TYPE}"
|
|
||||||
Header set X-Content-Type-Options "nosniff"
|
|
||||||
|
|
||||||
</IfModule>
|
|
||||||
48
deploy.php
48
deploy.php
@@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Gitea Webhook Deploy Handler
|
|
||||||
* Called by Gitea on push to main branch.
|
|
||||||
*
|
|
||||||
* Set DEPLOY_SECRET in Gitea webhook settings and
|
|
||||||
* configure the same value in the DEPLOY_SECRET env var.
|
|
||||||
*/
|
|
||||||
|
|
||||||
$secret = getenv('DEPLOY_SECRET') ?: '';
|
|
||||||
|
|
||||||
if (empty($secret)) {
|
|
||||||
http_response_code(500);
|
|
||||||
die('DEPLOY_SECRET not configured.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify Gitea HMAC-SHA256 signature
|
|
||||||
$signature = $_SERVER['HTTP_X_GITEA_SIGNATURE'] ?? '';
|
|
||||||
$body = file_get_contents('php://input');
|
|
||||||
$expected = hash_hmac('sha256', $body, $secret);
|
|
||||||
|
|
||||||
if (!hash_equals($expected, $signature)) {
|
|
||||||
http_response_code(403);
|
|
||||||
die('Invalid signature.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only act on push events
|
|
||||||
$event = $_SERVER['HTTP_X_GITEA_EVENT'] ?? '';
|
|
||||||
if ($event !== 'push') {
|
|
||||||
http_response_code(200);
|
|
||||||
die('Ignored: not a push event.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only deploy on main branch
|
|
||||||
$payload = json_decode($body, true);
|
|
||||||
$ref = $payload['ref'] ?? '';
|
|
||||||
if ($ref !== 'refs/heads/main') {
|
|
||||||
http_response_code(200);
|
|
||||||
die('Ignored: not main branch.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull latest and rebuild
|
|
||||||
putenv('HOME=/var/www');
|
|
||||||
$output = shell_exec('cd /var/www/html && git pull 2>&1 && git submodule update --init --recursive 2>&1 && hugo 2>&1');
|
|
||||||
|
|
||||||
http_response_code(200);
|
|
||||||
header('Content-Type: text/plain');
|
|
||||||
echo "Deploy triggered:\n" . $output;
|
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
robbis-space:
|
robbis-space:
|
||||||
build:
|
# Fertiges Image aus der Gitea-Registry. Die Seite ist beim Build
|
||||||
context: ./kirby
|
# hineingebacken - kein git pull, kein Hugo-Lauf zur Laufzeit.
|
||||||
dockerfile: Dockerfile
|
# Deployen heisst: docker compose pull && docker compose up -d
|
||||||
image: robbis-space
|
image: ${ROBBIS_IMAGE:-gitea.mindboost.team/rorapp/robbis.space:latest}
|
||||||
container_name: robbis-space
|
container_name: robbis-space
|
||||||
volumes:
|
|
||||||
- /home/kirbyuser/robbis-space:/var/www/html:rw # Persistente Daten
|
|
||||||
environment:
|
|
||||||
- DEPLOY_SECRET=dc2d9b0af4849284a0cb396d462aa1853df0c16fec45c5c859d6b97874ea8db4
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
- proxy
|
||||||
@@ -24,12 +18,12 @@ services:
|
|||||||
- "traefik.http.routers.robbis-space.entrypoints=websecure"
|
- "traefik.http.routers.robbis-space.entrypoints=websecure"
|
||||||
- "traefik.http.routers.robbis-space.tls=true"
|
- "traefik.http.routers.robbis-space.tls=true"
|
||||||
- "traefik.http.services.robbis-space.loadbalancer.server.port=80"
|
- "traefik.http.services.robbis-space.loadbalancer.server.port=80"
|
||||||
# HTTP-Router (Port 80)
|
# HTTP-Router (Port 80) mit Weiterleitung auf HTTPS
|
||||||
- "traefik.http.routers.robbis-space-http.rule=Host(`robbis.space`)"
|
- "traefik.http.routers.robbis-space-http.rule=Host(`robbis.space`)"
|
||||||
- "traefik.http.routers.robbis-space-http.entrypoints=web"
|
- "traefik.http.routers.robbis-space-http.entrypoints=web"
|
||||||
- "traefik.http.routers.robbis-space-http.middlewares=traefik-https-redirect"
|
- "traefik.http.routers.robbis-space-http.middlewares=traefik-https-redirect"
|
||||||
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
|
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
|
||||||
# Service-Port (nginx läuft auf Port 80 im Container)
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
33
docker/Dockerfile
Normal file
33
docker/Dockerfile
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Zweistufiger Build: Hugo erzeugt die Seite, nginx liefert nur noch aus.
|
||||||
|
# Das fertige HTML steckt im Image - zur Laufzeit wird nichts mehr gebaut
|
||||||
|
# oder aus git geholt.
|
||||||
|
|
||||||
|
FROM debian:bookworm-slim AS builder
|
||||||
|
|
||||||
|
ARG HUGO_VERSION=0.147.0
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
curl \
|
||||||
|
ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN curl -fsSL "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz" \
|
||||||
|
| tar -xz -C /usr/local/bin hugo
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# themes/gokarna ist ein Submodule und muss im Build-Context liegen.
|
||||||
|
# In der CI sorgt actions/checkout mit submodules:recursive dafuer.
|
||||||
|
RUN test -f themes/gokarna/theme.toml \
|
||||||
|
|| { echo "FEHLER: themes/gokarna fehlt - Submodule nicht ausgecheckt"; exit 1; }
|
||||||
|
|
||||||
|
RUN hugo --minify --destination /public
|
||||||
|
|
||||||
|
|
||||||
|
FROM nginx:1.27-alpine
|
||||||
|
|
||||||
|
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
COPY --from=builder /public /usr/share/nginx/html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
18
docker/nginx.conf
Normal file
18
docker/nginx.conf
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name robbis.space;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 404 /404.html;
|
||||||
|
|
||||||
|
location ~* \.(css|js|jpg|jpeg|png|gif|svg|webp|woff2?)$ {
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
FROM debian:bookworm-slim
|
|
||||||
|
|
||||||
# Install nginx, PHP-CLI, git, curl
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
nginx \
|
|
||||||
php-cli \
|
|
||||||
php-fpm \
|
|
||||||
git \
|
|
||||||
curl \
|
|
||||||
ca-certificates \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install Hugo (extended)
|
|
||||||
ARG HUGO_VERSION=0.147.0
|
|
||||||
RUN curl -L "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz" \
|
|
||||||
| tar -xz -C /usr/local/bin hugo
|
|
||||||
|
|
||||||
# nginx config
|
|
||||||
COPY nginx.conf /etc/nginx/sites-available/default
|
|
||||||
|
|
||||||
# PHP-FPM for deploy.php
|
|
||||||
RUN sed -i 's|listen = /run/php/php.*-fpm.sock|listen = 127.0.0.1:9000|' /etc/php/*/fpm/pool.d/www.conf \
|
|
||||||
&& sed -i 's|;clear_env = no|clear_env = no|' /etc/php/*/fpm/pool.d/www.conf \
|
|
||||||
|| echo 'clear_env = no' >> /etc/php/*/fpm/pool.d/www.conf
|
|
||||||
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
|
||||||
RUN chmod +x /entrypoint.sh
|
|
||||||
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Start PHP-FPM
|
|
||||||
PHP_FPM=$(find /usr/sbin -name 'php-fpm*' | head -1)
|
|
||||||
$PHP_FPM
|
|
||||||
|
|
||||||
# deploy.php laeuft als www-data, das Repo gehoert einem anderen Benutzer.
|
|
||||||
# Ohne diese Ausnahme bricht git mit "detected dubious ownership" ab und die
|
|
||||||
# &&-Kette in deploy.php erreicht hugo nie. --system gilt fuer alle Benutzer.
|
|
||||||
git config --system --add safe.directory /var/www/html
|
|
||||||
git config --system --add safe.directory /var/www/html/themes/gokarna
|
|
||||||
|
|
||||||
# www-data muss ins Repo schreiben koennen (git pull, hugo nach public/).
|
|
||||||
chown -R www-data:www-data /var/www/html || true
|
|
||||||
|
|
||||||
# Initial Hugo build
|
|
||||||
cd /var/www/html
|
|
||||||
git submodule update --init --recursive
|
|
||||||
hugo
|
|
||||||
|
|
||||||
# Start nginx in foreground
|
|
||||||
nginx -g 'daemon off;'
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name robbis.space;
|
|
||||||
|
|
||||||
root /var/www/html/public;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# Serve static Hugo output
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
# deploy.php webhook handler
|
|
||||||
location = /deploy.php {
|
|
||||||
root /var/www/html;
|
|
||||||
fastcgi_pass 127.0.0.1:9000;
|
|
||||||
fastcgi_index deploy.php;
|
|
||||||
include fastcgi_params;
|
|
||||||
fastcgi_param SCRIPT_FILENAME /var/www/html/deploy.php;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user