Compare commits

..
Author SHA1 Message Date
9c7e1ce4db Feature: Fehlerseiten 401, 403, 500, 502, 503, 504
Gemeinsames Layout in components/error-page.tsx, 404 darauf umgestellt.
Jede Route app/<code>/page.tsx erzeugt landingpage/<code>.html; die
Deploy-Skripte kopieren alle Fehlerseiten in den Webroot. README
dokumentiert die nötigen ErrorDocument-Zeilen (Server-Konfig unverändert).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:55:02 +02:00
ea2bcfbd27 Feature: Eigene 404-Seite im Landingpage-Stil
app/not-found.tsx erzeugt landingpage/404.html (Terminal-Look mit
angefragtem Pfad). Die Deploy-Skripte kopieren sie zusätzlich in den
Webroot, damit sie auch außerhalb von /landingpage/ greift.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:40:36 +02:00
99c6c9516c Content: Hero-Text überarbeitet, Mundorgel → Maultrommel, Jamulix-Gesetz
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:40:36 +02:00
15 changed files with 472 additions and 9 deletions

View file

@ -98,6 +98,7 @@ Die E-Mail im Footer (`footer.tsx`) wird als Prop von `app/page.tsx` übergeben:
- Öffnet eine SSH-Master-Verbindung (Passwort nur einmal eingeben) - Öffnet eine SSH-Master-Verbindung (Passwort nur einmal eingeben)
- rsync nach `jamulix.de:/var/www/jamulix.de/html/landingpage/` - rsync nach `jamulix.de:/var/www/jamulix.de/html/landingpage/`
- Setzt Symlink: `/var/www/jamulix.de/html/index.html` → `landingpage/index.html` - Setzt Symlink: `/var/www/jamulix.de/html/index.html` → `landingpage/index.html`
- Kopiert die Fehlerseiten `landingpage/<code>.html` in den Webroot
### Localhost (zum Testen) ### Localhost (zum Testen)
@ -107,6 +108,7 @@ Die E-Mail im Footer (`footer.tsx`) wird als Prop von `app/page.tsx` übergeben:
- rsync nach `/var/www/html/landingpage/` - rsync nach `/var/www/html/landingpage/`
- Symlink: `/var/www/html/index.html` → `landingpage/index.html` - Symlink: `/var/www/html/index.html` → `landingpage/index.html`
- Kopiert die Fehlerseiten in den Webroot
- `sudo chown -R www-data:www-data` - `sudo chown -R www-data:www-data`
### Warum `/landingpage/` als Unterverzeichnis? ### Warum `/landingpage/` als Unterverzeichnis?
@ -115,6 +117,39 @@ Die E-Mail im Footer (`footer.tsx`) wird als Prop von `app/page.tsx` übergeben:
unter `jamulix.de/` zu betreiben ohne Konflikte. rsync mit `--delete` löscht unter `jamulix.de/` zu betreiben ohne Konflikte. rsync mit `--delete` löscht
nur Dateien innerhalb von `landingpage/`, nicht andere Verzeichnisse im Webroot. nur Dateien innerhalb von `landingpage/`, nicht andere Verzeichnisse im Webroot.
### Fehlerseiten
| Code | Quelle | Thema |
|------|--------|-------|
| 401 | `app/401/page.tsx` | Autorisierung erforderlich |
| 403 | `app/403/page.tsx` | Zugriff verweigert |
| 404 | `app/not-found.tsx` | Seite nicht gefunden |
| 500 | `app/500/page.tsx` | Interner Serverfehler |
| 502 | `app/502/page.tsx` | Bad Gateway |
| 503 | `app/503/page.tsx` | Wartungsarbeiten |
| 504 | `app/504/page.tsx` | Gateway Timeout |
Gemeinsames Layout: `components/error-page.tsx`. Der Build erzeugt
`landingpage/<code>.html`; die Deploy-Skripte kopieren sie zusätzlich nach
`<webroot>/<code>.html`. Alle Asset-Pfade sind absolut (`/landingpage/_next/…`),
daher funktionieren die Kopien im Webroot genauso.
Damit Apache sie ausliefert, braucht die vHost-Konfiguration (nicht Teil
dieses Repos) z. B.:
```apache
ErrorDocument 401 /401.html
ErrorDocument 403 /403.html
ErrorDocument 404 /404.html
ErrorDocument 500 /500.html
ErrorDocument 502 /502.html
ErrorDocument 503 /503.html
ErrorDocument 504 /504.html
```
- `ErrorDocument 401` muss ein lokaler Pfad sein, keine vollständige URL.
- Die 401-Seite erscheint erst, wenn der Login-Dialog des Browsers abgebrochen wird.
--- ---
## Design ## Design

37
app/401/page.tsx Normal file
View file

@ -0,0 +1,37 @@
import { ErrorPage, Cmd, Out, Err } from '@/components/error-page'
export const metadata = {
title: '401 – Autorisierung erforderlich | Jamulix',
description: 'Parole? Dieser Bereich ist passwortgeschützt.',
robots: { index: false, follow: false },
}
export default function Unauthorized() {
return (
<ErrorPage
code={401}
label="Autorisierung erforderlich"
title="Parole?"
terminal={
<>
<Cmd>ssh gast@jamulix.de</Cmd>
<Err>gast@jamulix.de: Permission denied (publickey,password).</Err>
<Cmd>sudo !!</Cmd>
<Out>[sudo] Passwort für gast: ********</Out>
<Out>Sorry, try again.</Out>
<Out>[sudo] Passwort für gast: geheim</Out>
<Out>Sorry, try again.</Out>
<Out>[sudo] Passwort für gast: 123456</Out>
<Err>sudo: 3 incorrect password attempts</Err>
<Cmd>echo &quot;Sesam, öffne dich&quot;</Cmd>
<Out>Sesam, öffne dich</Out>
</>
}
tip={<>Tipp: <span className="text-accent">123456</span> ist es auch diesmal nicht.</>}
>
Dieser Bereich ist passwortgeschützt. Wer Zugangsdaten hat, lädt die
Seite einfach neu und meldet sich an – alle anderen bekommen immerhin
diese hübsche Fehlerseite.
</ErrorPage>
)
}

35
app/403/page.tsx Normal file
View file

@ -0,0 +1,35 @@
import { ErrorPage, Cmd, Out, Err } from '@/components/error-page'
import { RequestedPath } from '@/components/requested-path'
export const metadata = {
title: '403 – Zugriff verweigert | Jamulix',
description: 'Hier gilt chmod 000.',
robots: { index: false, follow: false },
}
export default function Forbidden() {
return (
<ErrorPage
code={403}
label="Zugriff verweigert"
title="Hier gilt chmod 000."
terminal={
<>
<Cmd>ls -l <RequestedPath /></Cmd>
<Err>ls: Zugriff auf &apos;<RequestedPath />&apos; nicht möglich: Keine Berechtigung</Err>
<Cmd>chmod 777 <RequestedPath /></Cmd>
<Err>chmod: Ändern der Zugriffsrechte nicht möglich: Operation nicht erlaubt</Err>
<Cmd>sudo chmod 777 <RequestedPath /></Cmd>
<Err>gast ist nicht in der sudoers-Datei. Dieser Vorfall wird gemeldet.</Err>
<Cmd>whoami</Cmd>
<Out>gast</Out>
</>
}
tip={<>Tipp: Auch root war einmal <span className="text-accent">gast</span>.</>}
>
Die Seite gibt es – nur eben nicht für dich. Manche Verzeichnisse
bleiben aus gutem Grund verschlossen, selbst nach 50 Jahren
Unix-Erfahrung und mit freundlichem Fragen.
</ErrorPage>
)
}

34
app/500/page.tsx Normal file
View file

@ -0,0 +1,34 @@
import { ErrorPage, Cmd, Out, Err, Code } from '@/components/error-page'
export const metadata = {
title: '500 – Interner Serverfehler | Jamulix',
description: 'Der Server hat sich verschluckt.',
robots: { index: false, follow: false },
}
export default function InternalServerError() {
return (
<ErrorPage
code={500}
label="Interner Serverfehler"
title="Der Server hat sich verschluckt."
terminal={
<>
<Cmd>./server --seite-ausliefern</Cmd>
<Err>Segmentation fault (core dumped)</Err>
<Cmd>gdb ./server core</Cmd>
<Out>#0 0x00000000 in ?? ()</Out>
<Out>#1 0x0000dead in seite_ausliefern (zeiger=NULL)</Out>
<Cmd>cat notfall.f</Cmd>
<Out>C WENN ALLES SCHIEFGEHT:</Out>
<Code> STOP 500</Code>
</>
}
tip={<>Tipp: Kurz warten, dann <span className="text-accent">F5</span> – das hilft öfter, als man denkt.</>}
>
Irgendwo im Maschinenraum ist ein Zeiger ins Leere gelaufen. Das ist
nicht deine Schuld. Der Fehler wird untersucht – vermutlich bei einer
Tasse Tee.
</ErrorPage>
)
}

33
app/502/page.tsx Normal file
View file

@ -0,0 +1,33 @@
import { ErrorPage, Cmd, Out, Err } from '@/components/error-page'
export const metadata = {
title: '502 – Bad Gateway | Jamulix',
description: 'Der Server hinter dem Server schweigt.',
robots: { index: false, follow: false },
}
export default function BadGateway() {
return (
<ErrorPage
code={502}
label="Bad Gateway"
title="Der Server hinter dem Server schweigt."
terminal={
<>
<Cmd>ping -c 3 backend</Cmd>
<Out>--- backend ping statistics ---</Out>
<Err>3 packets transmitted, 0 received, 100% packet loss</Err>
<Cmd>curl http://localhost:8080/</Cmd>
<Err>curl: (7) Failed to connect to localhost port 8080: Connection refused</Err>
<Cmd>echo &quot;Hallo? Jemand da?&quot; &gt; /dev/backend</Cmd>
<Out>…</Out>
</>
}
tip={<>Tipp: Der Dienst startet meist von selbst neu – in ein paar Minuten nochmal versuchen.</>}
>
Der Webserver ist da und hat brav weitergefragt – aber die Anwendung
dahinter antwortet gerade nicht. Wahrscheinlich startet sie neu oder
denkt über ihr Leben nach.
</ErrorPage>
)
}

31
app/503/page.tsx Normal file
View file

@ -0,0 +1,31 @@
import { ErrorPage, Cmd, Out, Code } from '@/components/error-page'
export const metadata = {
title: '503 – Wartungsarbeiten | Jamulix',
description: 'Der Server macht gerade Teepause.',
robots: { index: false, follow: false },
}
export default function ServiceUnavailable() {
return (
<ErrorPage
code={503}
label="Wartungsarbeiten"
title="Der Server macht gerade Teepause."
terminal={
<>
<Cmd>systemctl status jamulix</Cmd>
<Out>● jamulix.service – Jamulix Webdienst</Out>
<Code> Active: maintenance (Teepause) since vorhin</Code>
<Out> Tasks: 1 (Wasser kocht)</Out>
<Cmd>sleep 300 &amp;&amp; tee tasse.txt &lt; kanne</Cmd>
<Out>Earl Grey, heiß.</Out>
</>
}
tip={<>Tipp: Ein guter Tee zieht 3–5 Minuten – genau wie diese Wartung.</>}
>
Hier wird gerade gewartet, aktualisiert und ein wenig aufgeräumt.
Gleich ist alles wieder da – frisch gepatcht und gut gelaunt.
</ErrorPage>
)
}

32
app/504/page.tsx Normal file
View file

@ -0,0 +1,32 @@
import { ErrorPage, Cmd, Out, Err, Code } from '@/components/error-page'
export const metadata = {
title: '504 – Gateway Timeout | Jamulix',
description: 'Der Server denkt noch nach.',
robots: { index: false, follow: false },
}
export default function GatewayTimeout() {
return (
<ErrorPage
code={504}
label="Gateway Timeout"
title="Der Server denkt noch nach."
terminal={
<>
<Cmd>curl --max-time 60 http://backend/</Cmd>
<Err>curl: (28) Operation timed out after 60000 milliseconds</Err>
<Cmd>cat jobkarte.jcl</Cmd>
<Code>//JOB504 JOB (1976),&apos;SEITE&apos;,CLASS=A</Code>
<Out>JOB 504 IN WARTESCHLANGE – POSITION 42</Out>
<Out>VORAUSSICHTLICHE AUSGABE: MORGEN FRÜH AM SCHALTER</Out>
</>
}
tip={<>Tipp: 1976 kam das Ergebnis am nächsten Morgen – heute reicht meist ein Neuladen.</>}
>
Die Anwendung hinter dem Webserver braucht gerade länger als erlaubt.
Früher gab man seinen Lochkartenstapel ab und holte das Ergebnis am
nächsten Tag – so lange musst du hoffentlich nicht warten.
</ErrorPage>
)
}

36
app/not-found.tsx Normal file
View file

@ -0,0 +1,36 @@
import { ErrorPage, Cmd, Out, Err, Code } from '@/components/error-page'
import { RequestedPath } from '@/components/requested-path'
export const metadata = {
title: '404 – Seite nicht gefunden | Jamulix',
description: 'Diese Seite ist vom Lochkartenstapel gefallen.',
robots: { index: false, follow: true },
}
export default function NotFound() {
return (
<ErrorPage
code={404}
label="Seite nicht gefunden"
title="Diese Seite ist vom Lochkartenstapel gefallen."
terminal={
<>
<Cmd>cd <RequestedPath /></Cmd>
<Out>bash: cd: <RequestedPath />: Datei oder Verzeichnis nicht gefunden</Out>
<Cmd>find / -name &quot;seite&quot; 2&gt;/dev/null</Cmd>
<Cmd>cat seite.f</Cmd>
<Out>C GESTANZT 1976 – STAPEL LEIDER RUNTERGEFALLEN</Out>
<Code> GO TO 404</Code>
<Cmd>sudo !!</Cmd>
<Err>jamulix ist nicht in der sudoers-Datei. Dieser Vorfall wird gemeldet.</Err>
</>
}
tip={<>Tipp: Auch nach 50 Jahren hilft <span className="text-accent">ls</span> meistens weiter.</>}
>
Seit 50 Jahren Code – und trotzdem verlegt man gelegentlich etwas.
Die gesuchte Seite existiert nicht, nicht mehr oder noch nicht.
Vielleicht war auch nur ein übereifriges{' '}
<code className="font-mono text-sm text-accent">rm -rf</code> am Werk.
</ErrorPage>
)
}

View file

@ -119,7 +119,7 @@ export function AboutSection() {
Und so gilt für mich das erste Jamulix-Gesetz: Und so gilt für mich das erste Jamulix-Gesetz:
</p> </p>
<p className="font-mono text-xl lg:text-2xl text-accent mt-3"> <p className="font-mono text-xl lg:text-2xl text-accent mt-3">
Je schlauer, umso Linux! Je schlauer, desto Linux!
</p> </p>
</div> </div>

157
components/error-page.tsx Normal file
View file

@ -0,0 +1,157 @@
import type { ReactNode } from 'react'
import Link from 'next/link'
import { ArrowLeft, FolderGit2 } from 'lucide-react'
import { Button } from '@/components/ui/button'
/* Terminal lines — each renders one line incl. trailing newline inside <pre> */
export function Cmd({ children }: { children: ReactNode }) {
return (
<>
<span className="text-accent">$</span> {children}{'\n'}
</>
)
}
export function Out({ children }: { children: ReactNode }) {
return (
<>
<span className="text-muted-foreground">{children}</span>{'\n'}
</>
)
}
export function Err({ children }: { children: ReactNode }) {
return (
<>
<span className="text-destructive dark:text-red-400">{children}</span>{'\n'}
</>
)
}
export function Code({ children }: { children: ReactNode }) {
return (
<>
<span className="text-cyan-600 dark:text-cyan-400">{children}</span>{'\n'}
</>
)
}
export function Cursor() {
return (
<>
<span className="text-accent">$</span>{' '}
<span className="inline-block w-2 h-4 align-middle bg-foreground animate-pulse" />
</>
)
}
type ErrorPageProps = {
code: number
label: string
title: string
children: ReactNode
terminal: ReactNode
tip: ReactNode
}
export function ErrorPage({ code, label, title, children, terminal, tip }: ErrorPageProps) {
return (
<main className="relative min-h-screen flex flex-col overflow-hidden">
{/* Fly.io-style gradient mesh background (dark mode only) */}
<div className="absolute inset-0 bg-gradient-mesh hidden dark:block" />
{/* Subtle grid overlay */}
<div
className="absolute inset-0 opacity-[0.02] dark:opacity-[0.04]"
style={{
backgroundImage: `
linear-gradient(to right, currentColor 1px, transparent 1px),
linear-gradient(to bottom, currentColor 1px, transparent 1px)
`,
backgroundSize: '60px 60px',
}}
/>
{/* Logo */}
<div className="relative max-w-6xl w-full mx-auto px-6 lg:px-8">
<div className="flex items-center h-16 lg:h-20">
<Link
href="/"
className="font-mono text-lg tracking-tight text-foreground hover:text-accent transition-colors"
>
Jamulix
</Link>
</div>
</div>
<div className="relative flex-1 flex items-center">
<div className="max-w-6xl w-full mx-auto px-6 lg:px-8 py-12 lg:py-20">
<div className="grid lg:grid-cols-12 gap-12 lg:gap-16 items-center">
{/* Text Content */}
<div className="lg:col-span-6 space-y-8">
<div>
<span className="inline-block font-mono text-xs tracking-wider text-accent uppercase mb-4">
Fehler {code} · {label}
</span>
<p
aria-hidden="true"
className="font-serif font-bold text-8xl sm:text-9xl leading-none tracking-tighter text-foreground/90 dark:bg-gradient-to-r dark:from-cyan-400 dark:to-violet-400 dark:bg-clip-text dark:text-transparent"
>
{code}
</p>
<h1 className="mt-6 font-serif text-3xl sm:text-4xl lg:text-5xl leading-[1.1] tracking-tight text-balance">
{title}
</h1>
</div>
<p className="text-lg text-muted-foreground leading-relaxed max-w-xl">
{children}
</p>
<div className="flex flex-col sm:flex-row gap-4">
<Button asChild size="lg" className="group">
<Link href="/">
<ArrowLeft className="mr-2 size-4 transition-transform group-hover:-translate-x-0.5" />
cd ~ — Zur Startseite
</Link>
</Button>
<Button asChild variant="outline" size="lg" className="group">
<Link href="/#projekte">
<FolderGit2 className="mr-2 size-4" />
Projekte ansehen
</Link>
</Button>
</div>
</div>
{/* Terminal */}
<div className="lg:col-span-6">
<div className="rounded-lg border border-border bg-card shadow-xl dark:shadow-[0_0_40px_oklch(0.70_0.22_280/0.3)] overflow-hidden">
<div className="flex items-center gap-2 px-4 py-3 border-b border-border bg-muted/50">
<span className="size-3 rounded-full bg-red-500/80" />
<span className="size-3 rounded-full bg-yellow-500/80" />
<span className="size-3 rounded-full bg-green-500/80" />
<span className="ml-3 font-mono text-xs text-muted-foreground">
jamulix@jamulix.de: ~
</span>
</div>
<pre className="p-5 sm:p-6 font-mono text-xs sm:text-sm leading-relaxed whitespace-pre-wrap text-card-foreground">
{terminal}
<Cursor />
</pre>
</div>
<p className="mt-4 font-mono text-xs text-muted-foreground text-center lg:text-left">
{tip}
</p>
</div>
</div>
</div>
</div>
</main>
)
}

View file

@ -50,11 +50,14 @@ export function Hero() {
transition={{ duration: 0.6, delay: 0.1 }} transition={{ duration: 0.6, delay: 0.1 }}
className="text-lg lg:text-xl text-muted-foreground leading-relaxed max-w-2xl" className="text-lg lg:text-xl text-muted-foreground leading-relaxed max-w-2xl"
> >
Erste Programmiersprache: Fortran{'\u00A0'}IV im VWL-Studium. Seit 50 Jahren Code – angefangen mit Fortran IV auf Lochkarten.
Dann C und 68000-Assembler auf dem Atari{'\u00A0'}1040ST programmiert. Über C und 68000-Assembler auf dem Atari ST zu Unix an der Uni
An der Universität Unix entdeckt – und dann Linux, das mich nie wieder losgelassen hat. und dann zu Linux, das mich seit seinen Anfängen begleitet.
Seit Ende 2022 konzentriert auf KI-Tools und KI-Programmierung. Heute entwickle ich KI-Systeme und Agenten mit Python, Rust & Co,
Heute: KI, Python, Rust, C und vieles mehr. erstelle und nutze Agentensysteme sowie angrenzende Technologien
moderner Softwareentwicklung und des praktischen KI-Einsatzes.
Das Augenmerk liegt dabei auf neuen Methoden, digitaler Souveränität,
Open Source und Lizenzkostenersparnis.
</motion.p> </motion.p>
<motion.div <motion.div

View file

@ -25,12 +25,12 @@ const projects = [
featured: true, featured: true,
}, },
{ {
title: 'Digitalisierung einer "Mundorgel"', title: 'Digitalisierung einer "Maultrommel"',
slug: 'upcoming-1', slug: 'upcoming-1',
description: 'In unserer Gruppe wollen wir Lieder aus Schulzeit und Jugend der 60er- und 70er-Jahre singen. Die „Mundorgel" war damals weit verbreitet, doch heutige Ausgaben enthalten viele dieser Stücke nicht mehr. Antiquarische Exemplare sind selten und teuer, Kopien unpraktisch.\n\nIch habe daher eine alte Mundorgel mit KI-Tools digitalisiert und auf meinem Server durchsuchbar gemacht. So werden analoge Inhalte für moderne Nutzung erschließbar.\n\nDas Projekt diente auch dem Lernen: Die gleichen Verfahren lassen sich auf Bücher, Akten oder Zeitungen übertragen. Im Vergleich zur kürzlich digitalisierten Encyclopaedia Britannica von 1911 (28 Bände) ist mein Projekt klein – doch die zugrunde liegenden Prozesse sind dieselben.', description: 'Lieder aus der Schulzeit und Jugend der 60er- und 70er-Jahre singen? Die „Maultrommel" war damals weit verbreitet, doch heutige Ausgaben enthalten viele dieser Stücke nicht mehr. Antiquarische Exemplare sind selten und teuer, Kopien unpraktisch.\n\nIch habe daher eine alte Maultrommel mit KI-Tools digitalisiert und auf meinem Server durchsuchbar gemacht. So werden analoge Inhalte für moderne Nutzung erschließbar.\n\nDas Projekt diente auch dem Lernen: Die gleichen Verfahren lassen sich auf Bücher, Akten oder Zeitungen übertragen. Im Vergleich zur Anfang 2026 digitalisierten Encyclopaedia Britannica von 1911 (28 Bände) ist mein Projekt klein – doch die zugrunde liegenden Prozesse sind dieselben.',
tech: ['LLM-OCR', 'JSON', 'Typescript', 'Tailwind', 'Vibe-Coding'], tech: ['LLM-OCR', 'JSON', 'Typescript', 'Tailwind', 'Vibe-Coding'],
status: 'Aktiv', status: 'Aktiv',
url: 'https://jamulix.de/mundorgel/', url: 'https://jamulix.de/maultrommel/',
featured: false, featured: false,
}, },
{ {

View file

@ -0,0 +1,19 @@
'use client'
import { useEffect, useState } from 'react'
// Shows the requested URL path; falls back to a placeholder without JS
export function RequestedPath() {
const [path, setPath] = useState('/gesuchte-seite')
useEffect(() => {
const raw = window.location.pathname
try {
setPath(decodeURI(raw))
} catch {
setPath(raw) // malformed percent-encoding
}
}, [])
return <span className="break-all">{path}</span>
}

View file

@ -4,6 +4,7 @@
set -e set -e
LOCAL_DIR="/home/dschlueter/neue_jamulix.de_landing_page/jamulix.de_webpage_2" LOCAL_DIR="/home/dschlueter/neue_jamulix.de_landing_page/jamulix.de_webpage_2"
ERROR_PAGES="401 403 404 500 502 503 504"
cd "$LOCAL_DIR" cd "$LOCAL_DIR"
@ -17,6 +18,12 @@ echo "Setze symbolischen Link: index.html → landingpage/index.html"
sudo rm -f /var/www/html/index.html sudo rm -f /var/www/html/index.html
sudo ln -s landingpage/index.html /var/www/html/index.html sudo ln -s landingpage/index.html /var/www/html/index.html
echo "Kopiere Fehlerseiten: landingpage/<code>.html → <code>.html"
for c in $ERROR_PAGES; do
sudo cp "landingpage/$c.html" "/var/www/html/$c.html"
sudo chown www-data:www-data "/var/www/html/$c.html"
done
sudo chown -R www-data:www-data /var/www/html/landingpage/ sudo chown -R www-data:www-data /var/www/html/landingpage/
echo "" echo ""

View file

@ -8,6 +8,7 @@ REMOTE_HOST="jamulix.de"
REMOTE_DIR="/var/www/jamulix.de/html" REMOTE_DIR="/var/www/jamulix.de/html"
LOCAL_DIR="/home/dschlueter/neue_jamulix.de_landing_page/jamulix.de_webpage_2" LOCAL_DIR="/home/dschlueter/neue_jamulix.de_landing_page/jamulix.de_webpage_2"
SSH_SOCKET="/tmp/ssh-jamulix-deploy-$$" SSH_SOCKET="/tmp/ssh-jamulix-deploy-$$"
ERROR_PAGES="401 403 404 500 502 503 504"
cleanup() { cleanup() {
ssh -S "$SSH_SOCKET" -O exit "$REMOTE_USER@$REMOTE_HOST" 2>/dev/null || true ssh -S "$SSH_SOCKET" -O exit "$REMOTE_USER@$REMOTE_HOST" 2>/dev/null || true
@ -30,5 +31,8 @@ rsync -av --delete -e "ssh -S $SSH_SOCKET" landingpage/ "$REMOTE_USER@$REMOTE_HO
echo "Setze symbolischen Link: index.html → landingpage/index.html" echo "Setze symbolischen Link: index.html → landingpage/index.html"
ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "rm -f '$REMOTE_DIR/index.html' && ln -s landingpage/index.html '$REMOTE_DIR/index.html'" ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "rm -f '$REMOTE_DIR/index.html' && ln -s landingpage/index.html '$REMOTE_DIR/index.html'"
echo "Kopiere Fehlerseiten: landingpage/<code>.html → <code>.html"
ssh -S "$SSH_SOCKET" "$REMOTE_USER@$REMOTE_HOST" "for c in $ERROR_PAGES; do cp '$REMOTE_DIR'/landingpage/\$c.html '$REMOTE_DIR'/\$c.html; done"
echo "" echo ""
echo "Deployment abgeschlossen: https://jamulix.de" echo "Deployment abgeschlossen: https://jamulix.de"