From f63e403afde62f00d714c25b4ff3c1ab707e38e4 Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+studip@gmail.com>
Date: Wed, 4 Dec 2024 09:50:47 +0100
Subject: [PATCH] wip

---
 config/docker-files/7.2-Dockerfile | 25 ++++++-------
 config/docker-files/7.3-Dockerfile | 20 +++++-----
 config/docker-files/7.4-Dockerfile | 24 ++++++------
 config/docker-files/8.0-Dockerfile | 26 ++++++-------
 config/docker-files/8.1-Dockerfile | 25 +++++++------
 config/docker-files/8.2-Dockerfile | 26 ++++++-------
 config/docker-files/8.3-Dockerfile | 28 +++++++-------
 config/docker-files/8.4-Dockerfile | 28 +++++++-------
 lib/Commands/Compile.php           | 18 +++++++--
 web/assets/style.css               | 59 ++++++++++++++++++++++++-----
 web/index.php                      | 60 +++++++++++++++++++++---------
 11 files changed, 208 insertions(+), 131 deletions(-)

diff --git a/config/docker-files/7.2-Dockerfile b/config/docker-files/7.2-Dockerfile
index 1aa6b3c..b9d267a 100644
--- a/config/docker-files/7.2-Dockerfile
+++ b/config/docker-files/7.2-Dockerfile
@@ -18,27 +18,26 @@ RUN apt update && apt install -y --no-install-recommends \
         libxml2-dev \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
         locales \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
-
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg-dir --with-freetype-dir --with-webp-dir
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached & redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg-dir --with-freetype-dir --with-webp-dir \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
 RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/*
+    && pecl clear-cache \
 
 # Enable PS in gs
-RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
+    && sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
         /etc/ImageMagick-6/policy.xml
diff --git a/config/docker-files/7.3-Dockerfile b/config/docker-files/7.3-Dockerfile
index d664f6f..905c3a0 100644
--- a/config/docker-files/7.3-Dockerfile
+++ b/config/docker-files/7.3-Dockerfile
@@ -18,26 +18,26 @@ RUN apt update && apt install -y --no-install-recommends \
         libxml2-dev \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
         locales \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
 RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg-dir --with-freetype-dir --with-webp-dir
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+RUN docker-php-ext-configure gd --with-jpeg-dir --with-freetype-dir --with-webp-dir \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
 RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
 # Enable PS in gs
 RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
diff --git a/config/docker-files/7.4-Dockerfile b/config/docker-files/7.4-Dockerfile
index b0b8972..be4b2e1 100644
--- a/config/docker-files/7.4-Dockerfile
+++ b/config/docker-files/7.4-Dockerfile
@@ -18,26 +18,26 @@ RUN apt update && apt install -y --no-install-recommends \
         libxml2-dev \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
         locales \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp
-RUN docker-php-ext-install -j$(nproc) gd gettext intl opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached & redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp \
+    && docker-php-ext-install -j$(nproc) gd gettext intl opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
-RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && docker-php-source delete \
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
 # Enable PS in gs
 RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
diff --git a/config/docker-files/8.0-Dockerfile b/config/docker-files/8.0-Dockerfile
index 39c1c03..d90fa8d 100644
--- a/config/docker-files/8.0-Dockerfile
+++ b/config/docker-files/8.0-Dockerfile
@@ -18,27 +18,27 @@ RUN apt update && apt install -y --no-install-recommends \
         libxml2-dev \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
         locales \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached & redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
-RUN docker-php-source delete
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && docker-php-source delete
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
 # Enable PS in gs
-RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
+    && sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
         /etc/ImageMagick-6/policy.xml
diff --git a/config/docker-files/8.1-Dockerfile b/config/docker-files/8.1-Dockerfile
index e39d102..ba576ed 100644
--- a/config/docker-files/8.1-Dockerfile
+++ b/config/docker-files/8.1-Dockerfile
@@ -19,26 +19,27 @@ RUN apt update && apt install -y --no-install-recommends \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
         locales \
         vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached & redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
-RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && docker-php-source delete \
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
 # Enable PS in gs
-RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
+    && sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
         /etc/ImageMagick-6/policy.xml
diff --git a/config/docker-files/8.2-Dockerfile b/config/docker-files/8.2-Dockerfile
index d4594a2..ed87ae9 100644
--- a/config/docker-files/8.2-Dockerfile
+++ b/config/docker-files/8.2-Dockerfile
@@ -18,27 +18,27 @@ RUN apt update && apt install -y --no-install-recommends \
         libxml2-dev \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
         locales \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached & redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
-RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && docker-php-source delete \
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
 # Enable PS in gs
-RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
+    && sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
         /etc/ImageMagick-6/policy.xml
diff --git a/config/docker-files/8.3-Dockerfile b/config/docker-files/8.3-Dockerfile
index 481b393..f430b68 100644
--- a/config/docker-files/8.3-Dockerfile
+++ b/config/docker-files/8.3-Dockerfile
@@ -20,27 +20,27 @@ RUN apt update \
         libxml2-dev \
         locales \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached and redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis \
+    && docker-php-ext-enable memcached redis \
 
 # Cleanup
-RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && docker-php-source delete \
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
-# Enable PS in gs
-RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
+# Enable PS in gs \
+    && sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
         /etc/ImageMagick-6/policy.xml
diff --git a/config/docker-files/8.4-Dockerfile b/config/docker-files/8.4-Dockerfile
index 84c2a19..a19bbd3 100644
--- a/config/docker-files/8.4-Dockerfile
+++ b/config/docker-files/8.4-Dockerfile
@@ -1,4 +1,4 @@
-FROM php:8.4-rc-fpm
+FROM php:8.4-fpm
 
 # Install system requirements
 RUN apt update \
@@ -20,27 +20,27 @@ RUN apt update \
         libxml2-dev \
         locales \
         libmemcached11 libmemcachedutil2 build-essential libmemcached-dev libz-dev \
-        vim \
-    && rm -rf /var/lib/apt/lists/*
 
 # Install locales
-RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
+    && sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen \
     && sed -i -e 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \
     && dpkg-reconfigure --frontend=noninteractive locales \
-    && update-locale
+    && update-locale \
 
 # Install php extensions
-RUN docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp
-RUN docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip
-
-# Install Memcached and redis
-RUN pecl install memcached redis \
-    && docker-php-ext-enable memcached redis
+    && docker-php-ext-configure gd --with-jpeg --with-freetype --with-webp \
+    && docker-php-ext-install -j$(nproc) gd gettext intl mysqli opcache pdo_mysql pdo_pgsql soap xsl zip \
+    && pecl install memcached redis xdebug \
+    && docker-php-ext-enable memcached redis xdebug \
 
 # Cleanup
-RUN docker-php-source delete \
-    && apt-get autoremove --purge -y && apt-get autoclean -y && apt-get clean -y
+    && docker-php-source delete \
+    && apt-get autoremove --purge -y \
+    && apt-get autoclean -y \
+    && apt-get clean -y \
+    && rm -rf /var/lib/apt/lists/* \
+    && pecl clear-cache \
 
 # Enable PS in gs
-RUN sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
+    && sed -r -i_bak 's/rights="none" pattern="([EX]?PS[23]*|PDF)"/rights="read | write" pattern="\1"/' \
         /etc/ImageMagick-6/policy.xml
diff --git a/lib/Commands/Compile.php b/lib/Commands/Compile.php
index 6682398..ab7701d 100644
--- a/lib/Commands/Compile.php
+++ b/lib/Commands/Compile.php
@@ -136,7 +136,7 @@ final class Compile extends Command
         // Declare volumes
         $volumes = [
             [realpath($cwd . '/web'), '/usr/share/nginx/html/studip-dockerized-config.app', 'ro'],
-            [realpath($cwd . '/logs'), '/usr/share/nginx/html/logs', 'ro'],
+            [realpath($cwd . '/logs'), '/usr/share/nginx/html/logs'],
             [realpath($cwd . '/config.json'), '/usr/share/nginx/html/studip-dockerized-config.json', 'ro'],
             ...array_map(
                 fn(string $path, array $definition) => [
@@ -149,6 +149,7 @@ final class Compile extends Command
 
         // Nginx
         $creator->addService('nginx', 'nginx:alpine', [
+            'container_name' => 'nginx',
             'depends_on' => ['redis-server', 'memcached-server'],
             'ports' => array_merge(
                 Config::getInstance()->get('default') ? ['80:80', '443:443'] : [],
@@ -202,6 +203,7 @@ final class Compile extends Command
             $index = $this->getPHPVersionIndex($version, 'php');
 
             $creator->addService($index, null, [
+                'container_name' => "php-{$version}",
                 'build' => [
                     'context' => '.',
                     'dockerfile' => "{$cwd}/config/docker-files/{$version}-Dockerfile",
@@ -248,8 +250,15 @@ final class Compile extends Command
         $creator->addVolume('cache-data');
 
         $creator->addService('adminer', 'adminer', [
-            'restart' => 'always',
-            'ports'   => ['8044:8080'],
+            'container_name' => 'adminer',
+            'restart'        => 'always',
+            'ports'          => ['8044:8080'],
+        ]);
+
+        $creator->addService('dozzle', 'amir20/dozzle:latest', [
+            'container_name' => 'dozzle',
+            'volumes'        => ['/var/run/docker.sock:/var/run/docker.sock'],
+            'ports'          => ['8045:8080'],
         ]);
 
         return $creator->dump();
@@ -302,7 +311,8 @@ final class Compile extends Command
             ]);
 
             $creator->addServer([
-                'listen ' . $sslPort . ' default_server ssl http2',
+                'listen ' . $sslPort . ' default_server ssl',
+                'http2 on',
                 'client_max_body_size 64M',
                 'set $fastcgi_backend ' . $index . '_backend',
 
diff --git a/web/assets/style.css b/web/assets/style.css
index b1667cb..395d483 100644
--- a/web/assets/style.css
+++ b/web/assets/style.css
@@ -2,6 +2,11 @@
     --background-color: #ffffff;
     --hover-background-color: #ffeecc;
     --text-color: #000000;
+
+    --nav-height: 3em;
+    --nav-font-size: 2em;
+
+    --transition-duration: 300ms;
 }
 
 @media (prefers-color-scheme: dark) {
@@ -15,33 +20,45 @@
 body {
     background-color: var(--background-color);
     color: var(--text-color);
+    margin-top: calc(var(--nav-height) + var(--nav-font-size));
+}
+
+a {
+    transition: color var(--transition-duration);
+}
+a:hover {
+    color: red;
 }
 
 .tabs {
     background-color: inherit;
     border-bottom: 1px solid #ccc;
-    font-size: 1.5em;
-    line-height: 1.5em;
+    font-size: var(--nav-font-size);
+    line-height: 1;
     position: fixed;
     top: 0;
     left: 0;
     right: 0;
-    height: 1.5em;
-    padding: 0 1em;
+    height: var(--nav-font-size);
+    padding: 0 0.5em;
+
+    display: flex;
+    flex-direction: row;
+    gap: 1ex;
+    justify-content: flex-start;
+    align-items: center;
 }
 .tabs a {
+    flex: 0;
     text-decoration: none;
 }
 .tabs a:focus {
     font-weight: bold;
 }
-.tabs .right {
-    float: right;
+.tabs a.right {
+    margin-left: auto;
 }
 
-section {
-    padding-top: 1.5em;
-}
 section:not(:target) {
     display: none;
 }
@@ -56,3 +73,27 @@ th {
 tr:hover td {
     background-color: var(--hover-background-color);
 }
+
+#logs {
+    padding-top: var(--nav-font-size);
+}
+#logs-nav {
+    background-color: inherit;
+    border-bottom: 1px solid #ccc;
+    padding: 0 0.5em;
+    position: fixed;
+    top: calc(var(--nav-height) + var(--nav-font-size));
+    left: 0;
+    right: 0;
+
+}
+
+button.as-link {
+    border: 0;
+    background: none;
+    transition: color var(--transition-duration);
+}
+button.as-link:hover {
+    cursor: pointer;
+    color: red;
+}
\ No newline at end of file
diff --git a/web/index.php b/web/index.php
index c9735a4..82ff48a 100644
--- a/web/index.php
+++ b/web/index.php
@@ -1,6 +1,15 @@
 <?php
 require_once __DIR__ . '/LogParser.php';
 
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+    if (!empty($_POST['empty-log'])) {
+        file_put_contents(__DIR__ . '/../logs/php/error.log', '');
+    }
+
+    header('Location: ' . $_SERVER['REQUEST_URI']);
+    exit;
+}
+
 $config = json_decode(file_get_contents(__DIR__ . '/../studip-dockerized-config.json'), true);
 $versions = $config['php'];
 ksort($versions);
@@ -8,7 +17,7 @@ ksort($versions);
 $log = new LogParser(__DIR__ . '/../logs/php/error.log');
 ?>
 <!doctype html>
-<html>
+<html lang="en">
 <head>
     <link href="assets/style.css" type="text/css" rel="stylesheet">
     <script src="assets/script.js"></script>
@@ -16,18 +25,19 @@ $log = new LogParser(__DIR__ . '/../logs/php/error.log');
 </head>
 <body>
     <nav class="tabs">
-        <span class="active">
-            <a href="#sites">Sites</a>
-        </span>
-        <span>
-            <a href="#logs">Logs</a>
-        </span>
+        <a href="#sites" class="active">
+            Sites
+        </a>
+        <a href="#logs">
+            Logs
+        </a>
 
-        <span class="right">
-            <a href="http://localhost:8044?username=root" target="_blank">
-                Adminer
-            </a>
-        </span>
+        <a href="http://localhost:8044?username=root" target="_blank" class="right">
+            Adminer
+        </a>
+        <a href="http://localhost:8045" target="_blank">
+            Dozzle
+        </a>
     </nav>
 
     <section id="sites">
@@ -38,7 +48,11 @@ $log = new LogParser(__DIR__ . '/../logs/php/error.log');
             <thead>
                 <tr>
                     <th>Name</th>
-                    <th colspan="<?= count($config['php']) ?>"></th>
+                <? foreach (array_keys($versions) as $version): ?>
+                    <th colspan="2" style="text-align: center">
+                        <?= htmlentities($version) ?>
+                    </th>
+                <? endforeach; ?>
                 </tr>
             </thead>
             <tbody>
@@ -55,11 +69,13 @@ $log = new LogParser(__DIR__ . '/../logs/php/error.log');
                     </td>
                     <?php foreach ($versions as $version => [$port, $sslPort]): ?>
                         <td>
-                            <a href="http://localhost:<?= $port ?>/<?= htmlentities($path) ?>">
-                                <?= htmlentities($version) ?>
-                            </a>
                             <a href="https://localhost:<?= $sslPort ?>/<?= htmlentities($path) ?>">
-                                (SSL)
+                                https
+                            </a>
+                        </td>
+                        <td>
+                            <a href="http://localhost:<?= $port ?>/<?= htmlentities($path) ?>">
+                                http
                             </a>
                         </td>
                     <?php endforeach; ?>
@@ -72,6 +88,16 @@ $log = new LogParser(__DIR__ . '/../logs/php/error.log');
     </section>
 
     <section id="logs">
+        <nav id="logs-nav">
+            <form action="<?= $_SERVER['REQUEST_URI'] ?>"
+                  method="post"
+                  onsubmit="return confirm('Do you really want to empty the logs?');"
+            >
+                <button type="submit" name="empty-log" value="1" class="as-link">
+                    🗑️
+                </button>
+            </form>
+        </nav>
     <?php if ($log->hasData()): ?>
         <ul>
         <?php foreach ($log->entries() as $entry): ?>
-- 
GitLab