Skip to content

marcel-st/daily_dilbert

Repository files navigation

Daily Dilbert

Dockerized PHP/Apache deployment for the Daily Dilbert viewer.

At container startup, the entrypoint checks for comics in /var/www/html/comics. If the folder is missing or empty, it downloads and extracts:

  • https://cds.xocloud.nl/mta1ujxiq8ln1rl/dilbert-comics.tgz

What is included

  • Apache + PHP runtime image (php:8.3-apache)
  • Startup bootstrap script that downloads/extracts the comics archive
  • Docker Compose service for one-command deploys
  • Responsive comic viewer UI optimized for mobile, including stacked touch-friendly controls and improved landscape-phone behavior

Requirements

  • Docker Engine 24+ (or compatible)
  • Docker Compose v2 (docker compose)
  • Network access from the container to the comics archive URL

Quick start (recommended: Compose)

From this folder:

docker compose up -d --build

Then open:

  • http://localhost

Stop and remove container/network:

docker compose down

Quick start (plain Docker)

Build image:

docker build -t daily-dilbert:v1.1.0 .

Run container:

docker run -d --restart unless-stopped -p 80:80 --name daily-dilbert daily-dilbert:v1.1.0

Deploy to a remote Docker host

If your daemon is reachable over SSH:

export DOCKER_HOST=ssh://user@remote-host
docker compose up -d --build

Or with plain Docker:

export DOCKER_HOST=ssh://user@remote-host
docker build -t daily-dilbert:v1.1.0 .
docker run -d --restart unless-stopped -p 80:80 --name daily-dilbert daily-dilbert:v1.1.0

Configuration

Environment variables supported by the container:

  • COMICS_ARCHIVE_URL (default: https://cds.xocloud.nl/mta1ujxiq8ln1rl/dilbert-comics.tgz)
  • COMICS_ARCHIVE_SHA256 (default: 521749868533259f1a5d78baa594202bc8362cf9b60b35c0d315100f4a41a87e)
  • WEB_ROOT (default: /var/www/html)

Example:

docker run -d --restart unless-stopped -p 80:80 \
  -e COMICS_ARCHIVE_URL=https://example.org/dilbert-comics.tgz \
  -e COMICS_ARCHIVE_SHA256=<sha256-of-archive> \
  --name daily-dilbert daily-dilbert:v1.1.0

If you change COMICS_ARCHIVE_URL, always set the matching COMICS_ARCHIVE_SHA256 value. The container now refuses to extract archives when checksum verification fails.

Android download API

For native clients that only need the comic image (no web viewer rendering), use:

  • GET /api/current.php to fetch the latest comic (no query params required)
  • GET /api/comic.php?date=YYYY-MM-DD to fetch a comic for a specific date
  • GET /api/comic.php?latest=1 to fetch the most recent comic in the archive
  • add &download=1 to force attachment download behavior

Examples:

curl -L -o latest.gif "http://localhost/api/current.php"
curl -o comic.gif "http://localhost/api/comic.php?date=1989-04-16"
curl -L -o latest.gif "http://localhost/api/comic.php?latest=1"

HTTP caching policy

The image enables Apache response caching headers:

  • Comic images (*.gif): Cache-Control: public, max-age=31536000, immutable
  • Dynamic pages (*.php, *.html): Cache-Control: no-cache, private, must-revalidate

This policy is defined in apache-cache.conf and enabled during image build.

Updating comics data

Comics are downloaded only when /var/www/html/comics is missing or empty.

To force a fresh download:

  1. Remove the running container.
  2. Start a new container from the same image.

If you use persistent volumes for /var/www/html/comics, clear that volume content first.

Operational commands

Show logs:

docker logs -f daily-dilbert

Restart service (Compose):

docker compose restart

Rebuild after code changes:

docker compose up -d --build

Troubleshooting

  • permission denied /var/run/docker.sock: run commands with a user that has Docker daemon access.
  • comics not showing: check container logs and verify outbound access to cds.xocloud.nl.
  • port already in use: change host binding, for example -p 8080:80.

Mobile UX

The viewer is responsive and optimized for touch devices.

Behavior on small screens

  • Search and navigation controls stack into full-width rows on narrow viewports.
  • Buttons and input fields use larger touch targets for easier tapping.
  • Comic images scale to screen width and keep aspect ratio.
  • Extra layout tuning is applied for short-height landscape phone screens.
  • On mobile, comics can split into swipeable panels using detected white vertical separators between strips.
  • If separator detection does not find a reliable split, the viewer automatically falls back to the full comic image.

Quick verification checklist

Use browser device emulation or a real phone and validate:

  • Portrait ~390×844 (modern phone): search field + button are easy to tap.
  • Portrait ~320×568 (small phone): no horizontal scroll, controls remain readable.
  • Landscape with low height (for example ~844×390): title/search/nav remain visible without crowding.
  • Navigation buttons (Previous/Next) remain accessible after comic image loads.
  • Date search input opens native date picker and loads the matching comic.
  • Multi-strip comic on mobile: horizontal swipe moves cleanly between detected panels.
  • Comic without clear separators: full-image fallback is shown (no broken splits).

Server deployment checklist

Use this checklist when deploying to production.

1) Host and network

  • Docker Engine and Compose installed and updated.
  • Only required inbound ports are open:
    • 22/tcp (SSH, restricted)
    • 80/tcp and 443/tcp (web)
  • Outbound HTTPS (443/tcp) allowed so the container can download the comics archive.
  • Time sync enabled (systemd-timesyncd/NTP).

2) DNS

  • A/AAAA record points your domain to the server.
  • DNS propagated before enabling TLS.

3) Reverse proxy and TLS

  • Put the app behind a reverse proxy (Nginx, Caddy, or Traefik).
  • Enable HTTPS with a valid certificate (for example Let’s Encrypt).
  • Redirect HTTP to HTTPS.
  • Set X-Forwarded-Proto and Host headers correctly in proxy config.

4) Runtime and persistence

  • Container is started with restart policy (unless-stopped).
  • Decide persistence strategy for comics data:
    • no volume: comics downloaded on each fresh container
    • named/bind volume: comics cached across restarts/redeploys
  • Image and deployment commands are documented in your ops runbook.

5) Security hardening

  • SSH key auth only; password login disabled.
  • Root login via SSH disabled.
  • Host firewall enabled (ufw/nftables).
  • Automatic OS security updates enabled.
  • Reverse proxy adds basic security headers (HSTS, X-Content-Type-Options, X-Frame-Options).

6) Monitoring and backups

  • Container logs are collected/rotated (docker logs, journald, or external logging).
  • Basic uptime check configured (HTTP health endpoint or homepage check).
  • Backups defined for any persistent volumes and proxy config.
  • Restore procedure tested at least once.

7) Post-deploy validation

  • docker compose ps shows service healthy/running.
  • Homepage loads over HTTPS.
  • Comics list loads and image navigation works.
  • Restart test succeeds (docker compose restart).

Project files

  • Dockerfile: image definition
  • docker-entrypoint.sh: startup archive download/extract logic
  • docker-compose.yml: compose deployment definition
  • index.php, get_comics.php: web application

About

Daily Dilbert by Scott Adams - Blast from the past

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors