Pin image versions, add security headers, log limits, unattended upgrades

- Pin Miniflux to 2.2.19, Gitea to 1.25 (from :latest)
- Add security headers (X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy, Permissions-Policy) to all Caddy sites
- Add Docker JSON log rotation (10m x 3 files) to all containers
- Add SHA256 checksum verification for GoatCounter binary download
- Install and configure unattended-upgrades for security patches

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Louis Simoneau
2026-04-10 08:31:41 +10:00
parent a9e063867a
commit ab050fddd7
4 changed files with 78 additions and 2 deletions

View File

@@ -2,6 +2,14 @@ monotrope.au {
root * /var/www/monotrope root * /var/www/monotrope
file_server file_server
# Security headers
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
}
# Compression # Compression
encode zstd gzip encode zstd gzip
@@ -27,6 +35,13 @@ www.monotrope.au {
reader.monotrope.au { reader.monotrope.au {
reverse_proxy localhost:8080 reverse_proxy localhost:8080
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
}
encode zstd gzip encode zstd gzip
} }
@@ -34,6 +49,12 @@ reader.monotrope.au {
git.monotrope.au { git.monotrope.au {
reverse_proxy localhost:3000 reverse_proxy localhost:3000
header {
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
}
encode zstd gzip encode zstd gzip
} }
@@ -41,5 +62,12 @@ git.monotrope.au {
stats.monotrope.au { stats.monotrope.au {
reverse_proxy localhost:8081 reverse_proxy localhost:8081
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
}
encode zstd gzip encode zstd gzip
} }

View File

@@ -33,8 +33,35 @@
- apt-transport-https - apt-transport-https
- curl - curl
- ufw - ufw
- unattended-upgrades
state: present state: present
- name: Configure unattended-upgrades
copy:
dest: /etc/apt/apt.conf.d/50unattended-upgrades
owner: root
group: root
mode: '0644'
content: |
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
- name: Enable automatic updates
copy:
dest: /etc/apt/apt.conf.d/20auto-upgrades
owner: root
group: root
mode: '0644'
content: |
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
# ── Caddy ─────────────────────────────────────────────────────────────── # ── Caddy ───────────────────────────────────────────────────────────────
- name: Add Caddy GPG key - name: Add Caddy GPG key
@@ -309,6 +336,7 @@
url: "https://github.com/arp242/goatcounter/releases/download/v{{ goatcounter_version }}/goatcounter-v{{ goatcounter_version }}-linux-amd64.gz" url: "https://github.com/arp242/goatcounter/releases/download/v{{ goatcounter_version }}/goatcounter-v{{ goatcounter_version }}-linux-amd64.gz"
dest: /tmp/goatcounter.gz dest: /tmp/goatcounter.gz
mode: '0644' mode: '0644'
checksum: "sha256:98d221cb9c8ef2bf76d8daa9cca647839f8d8b0bb5bc7400ff9337c5da834511"
tags: goatcounter tags: goatcounter
- name: Decompress GoatCounter binary - name: Decompress GoatCounter binary

View File

@@ -1,7 +1,12 @@
services: services:
gitea: gitea:
image: gitea/gitea:latest image: gitea/gitea:1.25
restart: unless-stopped restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@@ -26,6 +31,11 @@ services:
db: db:
image: postgres:16-alpine image: postgres:16-alpine
restart: unless-stopped restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes: volumes:
- gitea_db:/var/lib/postgresql/data - gitea_db:/var/lib/postgresql/data
environment: environment:

View File

@@ -1,7 +1,12 @@
services: services:
miniflux: miniflux:
image: miniflux/miniflux:latest image: miniflux/miniflux:2.2.19
restart: unless-stopped restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
@@ -20,6 +25,11 @@ services:
db: db:
image: postgres:16-alpine image: postgres:16-alpine
restart: unless-stopped restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes: volumes:
- miniflux_db:/var/lib/postgresql/data - miniflux_db:/var/lib/postgresql/data
environment: environment: