12 Commits

Author SHA1 Message Date
5a51420d5e fix mathjax config 2026-06-05 16:22:37 -07:00
f092e99c6b keep mysql password inside container to avoid host process table exposure 2026-05-08 18:23:46 -07:00
d79b9a9a1d replace subprocess shell calls with pathlib in backup canary to prevent shell injection 2026-05-08 18:23:43 -07:00
942d75dd86 disable raw HTML in mediawiki to prevent stored XSS 2026-05-08 18:23:39 -07:00
1e8af71026 add docker socket proxy to protect against unrestricted host access from gitea runner 2026-05-08 18:23:36 -07:00
e8235f246f update .gitignore 2026-05-08 18:23:31 -07:00
4ea40c091e Merge branch 'stupid-goddamn-mysql'
* stupid-goddamn-mysql:
  fix stupid goddamn mysql secret volume
2026-04-21 11:33:36 -07:00
7f61795ad9 fix stupid goddamn mysql secret volume 2026-04-21 11:33:24 -07:00
6e52b56302 Merge branch 'optimize-mw-dockerfile'
* optimize-mw-dockerfile:
  fix d-mediawiki dockerfile
2026-04-21 11:01:03 -07:00
8926e6c33b Merge branch 'gitea-actions'
* gitea-actions:
  remove unused data vol
  fix networking issues in gitea action runner
  fix stupid volume issue
  upgrade mediawiki (AGAIN)
  pod-charlesreid1 service: stdout journal
  remove endless tex packages from mw Dockerfile
  fix edit box style
  add runner config dir
  add gitea runner config
  get gitea container set up for gitea actions
2026-04-21 11:00:54 -07:00
e5b56493e8 fix d-mediawiki dockerfile 2026-04-21 10:58:46 -07:00
3ec56cb967 remove unused data vol 2026-04-19 23:04:02 -07:00
7 changed files with 70 additions and 49 deletions

2
.gitignore vendored
View File

@@ -29,4 +29,4 @@ site
root.password
docker-compose.yml
*.zip
.claude

View File

@@ -5,7 +5,7 @@ EXPOSE 8989
# Install ImageMagick (used for image thumbnailing)
RUN apt-get update && \
apt-get install -y imagemagick && \
apt-get install -y --no-install-recommends imagemagick && \
rm -rf /var/lib/apt/lists/*
# Copy skins, config files, and other particulars into container
@@ -24,28 +24,25 @@ RUN apt-get update && \
COPY charlesreid1-config/mediawiki/extensions/Math /var/www/html/extensions/Math
COPY charlesreid1-config/mediawiki/extensions/ParserFunctions /var/www/html/extensions/ParserFunctions
COPY charlesreid1-config/mediawiki/extensions/SyntaxHighlight_GeSHi /var/www/html/extensions/SyntaxHighlight_GeSHi
RUN chown -R www-data:www-data /var/www/html/*
# Skins
COPY charlesreid1-config/mediawiki/skins /var/www/html/skins
RUN chown -R www-data:www-data /var/www/html/skins
RUN touch /var/www/html/skins
# MathJax 3.2.2 (self-hosted, served via Apache alias at /w/mathjax/*).
# Math extension runs in 'source' mode; MathJax renders client-side, so we
# never call out to restbase/mathoid. See LocalSettings.php.j2.
COPY charlesreid1-config/mediawiki/mathjax /var/www/html/mathjax
RUN chown -R www-data:www-data /var/www/html/mathjax
# Settings
COPY charlesreid1-config/mediawiki/LocalSettings.php /var/www/html/LocalSettings.php
RUN chown -R www-data:www-data /var/www/html/LocalSettings*
RUN chmod 600 /var/www/html/LocalSettings.php
# Apache conf file
COPY charlesreid1-config/apache/*.conf /etc/apache2/sites-enabled/
RUN a2enmod rewrite
RUN service apache2 restart
RUN chown -R www-data:www-data /var/www/html/* /var/www/html/skins /var/www/html/mathjax /var/www/html/LocalSettings* && \
touch /var/www/html/skins && \
chmod 600 /var/www/html/LocalSettings.php && \
a2enmod rewrite
# PHP conf file
# https://hub.docker.com/_/php/

View File

@@ -93,14 +93,24 @@ $wgMathValidModes = [ 'source' ];
# which breaks air-gapped installs even when we only emit source HTML.
$wgMathDisableTexFilter = 'always';
$wgHooks['BeforePageDisplay'][] = function ( $out, $skin ) {
$out->addHeadItem( 'mathjax',
'<script>window.MathJax = {'
. 'tex: { inlineMath: [["$","$"],["\\\\(","\\\\)"]], '
. 'displayMath: [["$$","$$"],["\\\\[","\\\\]"]], '
. 'processEscapes: true }, '
. 'options: { processHtmlClass: "mwe-math-fallback-source-inline|mwe-math-fallback-source-display|mwe-math-element" } '
. '};</script>'
. '<script async src="/w/mathjax/tex-chtml.js"></script>'
$out->addHeadItem( 'mathjax-config',
'<script>'
. 'window.MathJax = {'
. ' tex: {'
. ' inlineMath: [["$","$"],["\\\\(","\\\\)"]],'
. ' displayMath: [["$$","$$"],["\\\\[","\\\\]"]],'
. ' processEscapes: true'
. ' },'
. ' options: {'
. ' enableMenu: false,'
. ' renderActions: { addMenu: [] }'
. ' },'
. ' startup: { typeset: true }'
. '};'
. '</script>'
);
$out->addHeadItem( 'mathjax-script',
'<script defer src="/w/mathjax/tex-chtml.js"></script>'
);
};
@@ -238,7 +248,7 @@ $wgSecureLogin = true;
###################################
# Raw html
$wgRawHtml = true;
$wgRawHtml = false;
# but also keep things locked down
$wgUseRCPatrol=true;

View File

@@ -1,7 +1,2 @@
FROM mysql:8.0
MAINTAINER charles@charlesreid1.com
# make mysql data a volume
VOLUME ["/var/lib/mysql"]
RUN chown mysql:mysql /var/lib/mysql

View File

@@ -27,19 +27,44 @@ services:
networks:
- frontend
docker_socket_proxy:
image: tecnativa/docker-socket-proxy:latest
container_name: docker_socket_proxy
restart: always
privileged: true
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
environment:
- CONTAINERS=1
- IMAGES=1
- NETWORKS=1
- VOLUMES=1
- EXEC=1
- POST=1
- ALLOW_START=1
- ALLOW_STOP=1
- ALLOW_RESTARTS=1
logging:
driver: "json-file"
options:
max-size: 1m
max-file: "10"
networks:
- frontend
stormy_gitea_runner:
image: gitea/act_runner:latest
container_name: stormy_gitea_runner
restart: always
volumes:
- "stormy_gitea_runner_data:/data"
- "/var/run/docker.sock:/var/run/docker.sock"
- "./d-gitea/runner/config.yaml:/etc/act_runner/config.yaml:ro"
environment:
- GITEA_INSTANCE_URL=http://stormy_gitea:3000
- GITEA_RUNNER_REGISTRATION_TOKEN={{ pod_charlesreid1_gitea_runner_token }}
- GITEA_RUNNER_NAME=stormy-runner
- CONFIG_FILE=/etc/act_runner/config.yaml
- DOCKER_HOST=tcp://docker_socket_proxy:2375
logging:
driver: "json-file"
options:
@@ -47,6 +72,7 @@ services:
max-file: "10"
depends_on:
- stormy_gitea
- docker_socket_proxy
networks:
- frontend
@@ -132,8 +158,6 @@ volumes:
stormy_mysql_data:
stormy_mw_images:
external: true
stormy_mw_data:
external: true
stormy_gitea_data:
stormy_gitea_runner_data:
stormy_nginx_logs:

View File

@@ -1,10 +1,12 @@
import os
import sys
import json
import socket
import time
from pathlib import Path
import requests
import boto3
import botocore
import subprocess
webhook_url = os.environ['POD_CHARLESREID1_CANARY_WEBHOOK']
@@ -24,18 +26,21 @@ def main():
alert(msg)
# verify there is a backup newer than N days
newer_backups = subprocess.getoutput(f'find {backup_dir}/* -mtime -{N}').split('\n')
if len(newer_backups)==1 and newer_backups[0]=='':
backup_path = Path(backup_dir)
cutoff = time.time() - (N * 86400)
newer_backups = [p for p in backup_path.iterdir() if p.stat().st_mtime > cutoff]
if not newer_backups:
msg = "Local Backups Error:\n"
msg += f"The backup directory `{backup_dir}` is missing backup files from the last {N} day(s)!"
alert(msg)
newest_backup_name = subprocess.getoutput(f'ls -t {backup_dir} | head -n1')
newest_backup_path = os.path.join(backup_dir, newest_backup_name)
newest_backup_files = subprocess.getoutput(f'find {newest_backup_path} -type f').split('\n')
newest_backup = max(backup_path.iterdir(), key=lambda p: p.stat().st_mtime)
newest_backup_name = newest_backup.name
newest_backup_path = str(newest_backup)
newest_backup_files = [str(p) for p in newest_backup.rglob('*') if p.is_file()]
# verify the most recent backup directory is not empty
if len(newest_backup_files)==1 and newest_backup_files[0]=='':
if not newest_backup_files:
msg = "Local Backups Error:\n"
msg += f"The most recent backup directory `{newest_backup_path}` is empty!"
alert(msg)
@@ -92,7 +97,7 @@ def check_exists(bucket_name, bucket_path):
def alert(msg):
title = ":bangbang: pod-charlesreid1 backups canary"
hostname = subprocess.getoutput('hostname')
hostname = socket.gethostname()
msg += f"\n\nHost: {hostname}"
slack_data = {
"username": "backups_canary",

View File

@@ -53,20 +53,12 @@ if [ "$#" == "0" ]; then
echo "Running mysqldump inside the mysql container"
# Pull the root password out of the container so we don't duplicate the
# secret on the host, and forward it in via MYSQL_PWD (which mysqldump
# reads automatically). No -t: a PTY corrupts --default-character-set=binary
# output (LF→CRLF translation on binary blobs) and its small kernel buffer
# can deadlock on large dumps.
set +x
MYSQL_PWD="$(docker exec "${CONTAINER_NAME}" printenv MYSQL_ROOT_PASSWORD)"
export MYSQL_PWD
set -x
# The container already has MYSQL_ROOT_PASSWORD in its environment.
# Use it directly inside the container via MYSQL_PWD so the password
# never appears in the host process table.
docker exec -i \
-e MYSQL_PWD \
"${CONTAINER_NAME}" \
sh -c 'exec mysqldump \
sh -c 'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" exec mysqldump \
--user=root \
--single-transaction \
--quick \
@@ -77,8 +69,6 @@ if [ "$#" == "0" ]; then
--databases wikidb' \
> "${BACKUP_TARGET}"
unset MYSQL_PWD
# A complete mysqldump always ends with "-- Dump completed on ...".
# Missing trailer means the dump is truncated and not restorable.
if ! tail -c 200 "${BACKUP_TARGET}" | grep -q 'Dump completed on'; then