Last active
August 22, 2025 19:49
-
-
Save sbassett29/d12e3e09f0b6e81c985efe35b389ac46 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/usr/bin/env bash | |
################################################################################ | |
# Author: [email protected] | |
# License: MIT <https://opensource.org/license/mit> | |
# Usage: | |
# A basic mediawiki installation manager | |
# (with set -u, script will exit if the above are not defined) | |
# Based upon: https://gist.github.com/m-radzikowski/53e0b39e9a59a1518990e76c2bff8038 | |
################################################################################ | |
set -Eeuo pipefail | |
trap cleanup SIGINT SIGTERM ERR EXIT | |
# variables | |
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) | |
dir_uniqid='x' | |
git_branch='master' | |
git_clone_depth=0 | |
mw_core_repo_url='https://gerrit.wikimedia.org/r/mediawiki/core' | |
mw_core_dir=. | |
mw_skins_dir="skins" | |
mw_exts_dir="extensions" | |
mw_server_url="https://localhost:8443" | |
mw_docker_port="8081" | |
# functions | |
usage() { | |
cat <<EOF | |
Usage: $(basename "${BASH_SOURCE[0]}") [-hbus] {args} | |
A bash script to help quickly set up local copies of | |
MediaWiki and various Wikimedia-deployed extensions, skins. | |
Available options: | |
-h, --help Print this help and exit | |
-b, --branch {arg} The branch to clone | |
(default: master) | |
-u, --uniqid {arg} A phab task id or gerrit id, for dir naming | |
(default: 8-digit unique id) | |
-d, --deep Perform deep git clones | |
(default: shallow clones) | |
-k, --kill {arg} Kill running, related docker containers | |
and delete dir if {arg} is provided | |
EOF | |
exit | |
} | |
cleanup() { | |
trap - SIGINT SIGTERM ERR EXIT | |
} | |
msg() { | |
echo >&2 -e "${1-}" | |
} | |
die() { | |
local msg=$1 | |
local code=${2-1} # default exit status 1 | |
msg "$msg" | |
exit "$code" | |
} | |
parse_params() { | |
while [[ "$#" -gt 0 ]]; do | |
case "$1" in | |
-h | --help) usage ;; | |
-b | --branch) | |
if [[ -z "${2-}" ]]; then die "Error: No value supplied with ${1} option!"; fi; | |
git_branch="${2-}" | |
shift | |
;; | |
-u | --uniqid) | |
if [ -z "${2-}" ]; then die "Error: No value supplied with ${1} option!"; fi; | |
dir_uniqid="${2-}" | |
shift | |
;; | |
-d | --deep) | |
git_clone_depth=1 | |
shift | |
;; | |
-k | --kill) | |
kill_docker_and_dir "${2-}" | |
die "" | |
;; | |
-?*) die "Unknown option: $1" ;; | |
*) break ;; | |
esac | |
shift | |
done | |
return 0 | |
} | |
check_deps() { | |
bins=('git' 'uuidgen' 'sha256sum' 'basename' 'docker') | |
for bin in "${bins[@]}"; do | |
if [[ -z $(which $bin) ]]; then | |
die "dependency '$bin' does not appear to be installed - exiting.\n" | |
fi | |
done | |
} | |
create_uniqid() { | |
printf $(uuidgen | sha256sum | head -c 8) | |
} | |
process_global_options() { | |
mw_core_dir="$(basename $mw_core_repo_url)-${git_branch}-${dir_uniqid}" | |
if [[ $dir_uniqid == "x" ]]; then | |
dir_uniqid=$(create_uniqid) | |
fi | |
if [[ $git_clone_depth -eq 0 ]]; then | |
git_clone_depth='--depth=1' | |
fi | |
} | |
kill_docker_and_dir() { | |
docker ps -a | |
if [[ ! -z "${1-}" ]]; then | |
mw_core_dir="${1-}" | |
if [[ -d $mw_core_dir ]]; then | |
cd "$mw_core_dir" | |
docker compose down | |
cd .. | |
rm -rf "$mw_core_dir" | |
fi | |
else | |
# just try to stop/rm all running dockers | |
docker container stop $(docker container ls -aq) && docker container rm $(docker container ls -aq) | |
fi | |
# for good measure | |
docker system prune --force | |
docker ps -a | |
} | |
clone_mw_core() { | |
# assumes process_global_options has run | |
if [[ -d $mw_core_dir ]]; then | |
msg "Warning: ${mw_core_dir} exists already! Using a new, random uniqid for the core dir name..." | |
dir_uniqid=$(create_uniqid) | |
process_global_options | |
fi | |
cmd="git clone -b ${git_branch} --single-branch ${git_clone_depth} ${mw_core_repo_url} ${mw_core_dir}" | |
msg "Running: ${cmd}" | |
$cmd | |
} | |
config_mw_core() { | |
# assumes process_global_options has run | |
cd "$mw_core_dir" | |
# set .env | |
echo "MW_SCRIPT_PATH=/w | |
MW_SERVER=${mw_server_url} | |
MW_DOCKER_PORT=${mw_docker_port} | |
MEDIAWIKI_USER=Admin | |
MEDIAWIKI_PASSWORD=dockerpass | |
XDEBUG_CONFIG= | |
XDEBUG_ENABLE=true | |
XHPROF_ENABLE=true" >> .env | |
echo "MW_DOCKER_UID=$(id -u) | |
MW_DOCKER_GID=$(id -g)" >> .env | |
# run docker commands | |
docker compose up -d | |
docker compose exec mediawiki composer update | |
docker compose exec mediawiki /bin/bash /docker/install.sh | |
docker compose exec mediawiki git config --add safe.directory '*' | |
} | |
clone_mw_vector_skin() { | |
# assumes we're still in mw install dir | |
cd "$mw_skins_dir" | |
git clone -b ${git_branch} --single-branch ${git_clone_depth} "https://gerrit.wikimedia.org/r/mediawiki/skins/Vector" | |
docker compose exec -i mediawiki bash -c "cd ${mw_skins_dir}/Vector && composer update --no-dev" | |
cd .. | |
echo "wfLoadSkin( 'Vector' );" >> LocalSettings.php | |
} | |
clone_mw_extensions() { | |
# oath | |
cd "$mw_exts_dir" | |
git clone -b ${git_branch} --single-branch ${git_clone_depth} "https://gerrit.wikimedia.org/r/mediawiki/extensions/OATHAuth" | |
docker compose exec -i mediawiki bash -c "cd ${mw_exts_dir}/OATHAuth && composer update --no-dev" | |
cd .. | |
echo "wfLoadExtension( 'OATHAuth' );" >> LocalSettings.php | |
echo "\$wgGroupPermissions['user']['oathauth-enable'] = true;" >> LocalSettings.php | |
docker compose exec mediawiki php maintenance/run.php update.php | |
# webauthn | |
cd "$mw_exts_dir" | |
git clone -b ${git_branch} --single-branch ${git_clone_depth} "https://gerrit.wikimedia.org/r/mediawiki/extensions/WebAuthn" | |
docker compose exec -i mediawiki bash -c "cd ${mw_exts_dir}/WebAuthn && composer update --no-dev" | |
cd .. | |
echo "wfLoadExtension( 'WebAuthn' );" >> LocalSettings.php | |
echo "\$wgWebAuthnLimitPasskeysToRoaming = true;" >> LocalSettings.php | |
docker compose exec mediawiki php maintenance/run.php update.php | |
} | |
setup_mw_envoy_tls() { | |
# assumes process_global_options has run | |
cd "$mw_core_dir" | |
# amend docker compose to support envoy tls | |
# https://w.wiki/F6Sj | |
if [[ -f 'docker-compose.yml' ]]; then | |
echo ' | |
envoy: | |
image: envoyproxy/envoy:v1.25-latest | |
ports: | |
- "8443:443" | |
- "9901:9901" | |
volumes: | |
- ./envoy.yaml:/etc/envoy/envoy.yaml | |
- ./certs:/etc/envoy/certs | |
depends_on: | |
- mediawiki-web' >> docker-compose.yml | |
fi | |
# create dev certs | |
mkdir certs | |
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ | |
-keyout certs/server.key -out certs/server.crt \ | |
-subj "/CN=localhost" | |
# write basic envoy.yaml config | |
echo 'static_resources: | |
listeners: | |
- name: https_listener | |
address: | |
socket_address: | |
address: 0.0.0.0 | |
port_value: 443 | |
filter_chains: | |
- filters: | |
- name: envoy.filters.network.http_connection_manager | |
typed_config: | |
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager | |
codec_type: AUTO | |
stat_prefix: ingress_http | |
route_config: | |
name: local_route | |
virtual_hosts: | |
- name: local_service | |
domains: ["*"] | |
routes: | |
- match: | |
prefix: "/" | |
route: | |
cluster: mediawiki_cluster | |
http_filters: | |
- name: envoy.filters.http.router | |
typed_config: | |
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router | |
transport_socket: | |
name: envoy.transport_sockets.tls | |
typed_config: | |
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext | |
common_tls_context: | |
tls_certificates: | |
- certificate_chain: | |
filename: "/etc/envoy/certs/server.crt" | |
private_key: | |
filename: "/etc/envoy/certs/server.key" | |
clusters: | |
- name: mediawiki_cluster | |
connect_timeout: 1s | |
type: STRICT_DNS | |
lb_policy: ROUND_ROBIN | |
load_assignment: | |
cluster_name: mediawiki_cluster | |
endpoints: | |
- lb_endpoints: | |
- endpoint: | |
address: | |
socket_address: | |
address: mediawiki-web | |
port_value: 8080 | |
admin: | |
address: | |
socket_address: | |
address: 0.0.0.0 | |
port_value: 9901' >> envoy.yaml | |
cd .. | |
} | |
# main | |
parse_params "$@" | |
check_deps | |
process_global_options | |
clone_mw_core | |
setup_mw_envoy_tls | |
config_mw_core | |
clone_mw_vector_skin | |
clone_mw_extensions |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment