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:
|
||||
robbis-space:
|
||||
build:
|
||||
context: ./kirby
|
||||
dockerfile: Dockerfile
|
||||
image: robbis-space
|
||||
# Fertiges Image aus der Gitea-Registry. Die Seite ist beim Build
|
||||
# hineingebacken - kein git pull, kein Hugo-Lauf zur Laufzeit.
|
||||
# Deployen heisst: docker compose pull && docker compose up -d
|
||||
image: ${ROBBIS_IMAGE:-gitea.mindboost.team/rorapp/robbis.space:latest}
|
||||
container_name: robbis-space
|
||||
volumes:
|
||||
- /home/kirbyuser/robbis-space:/var/www/html:rw # Persistente Daten
|
||||
environment:
|
||||
- DEPLOY_SECRET=dc2d9b0af4849284a0cb396d462aa1853df0c16fec45c5c859d6b97874ea8db4
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- proxy
|
||||
@@ -24,12 +18,12 @@ services:
|
||||
- "traefik.http.routers.robbis-space.entrypoints=websecure"
|
||||
- "traefik.http.routers.robbis-space.tls=true"
|
||||
- "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.entrypoints=web"
|
||||
- "traefik.http.routers.robbis-space-http.middlewares=traefik-https-redirect"
|
||||
- "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
|
||||
# Service-Port (nginx läuft auf Port 80 im Container)
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
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