From b21c041ce914959720995744c3ca72cf8f85c6a5 Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Fri, 24 Apr 2026 15:33:57 +0200 Subject: [PATCH 1/3] working local docker compose setup --- .gitignore | 1 + Containerfile | 28 ++++++++++++ docker-compose.yml | 67 ++++++++++++++++++++++++++++ docker-compose/PrivatePAUSE.pm | 52 +++++++++++++++++++++ docker-compose/mysql/03_fixtures.sql | 6 +++ docker-compose/nginx/default.conf | 46 +++++++++++++++++++ docker-compose/setup.sh | 21 +++++++++ docker-compose/tmp/readme | 1 + 8 files changed, 222 insertions(+) create mode 100644 Containerfile create mode 100644 docker-compose.yml create mode 100644 docker-compose/PrivatePAUSE.pm create mode 100644 docker-compose/mysql/03_fixtures.sql create mode 100644 docker-compose/nginx/default.conf create mode 100755 docker-compose/setup.sh create mode 100644 docker-compose/tmp/readme diff --git a/.gitignore b/.gitignore index 034741d03..19c4a75e3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ pm_to_blib mailer.testfile privatelib cover_db +docker-compose/tmp/ diff --git a/Containerfile b/Containerfile new file mode 100644 index 000000000..cd8e48428 --- /dev/null +++ b/Containerfile @@ -0,0 +1,28 @@ +FROM perl:5.42-bookworm + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + libdb-dev libexpat1-dev libgetopt-long-descriptive-perl libpath-tiny-perl libsasl2-modules zlib1g-dev unzip tree vim \ + && rm -fr /var/cache/apt/* /var/lib/apt/lists/* + +RUN useradd -m --shell /bin/bash pause +WORKDIR /home/pause + +COPY cpanfile cpanfile +RUN cpanm -n --installdeps . + +COPY docker-compose/setup.sh /setup.sh +RUN /setup.sh + +USER pause + +COPY --chown=pause docker-compose/PrivatePAUSE.pm privatelib/PrivatePAUSE.pm +COPY --chown=pause t t +COPY --chown=pause doc doc +COPY --chown=pause htdocs htdocs +COPY --chown=pause cron cron +COPY --chown=pause bin bin +COPY --chown=pause lib lib +COPY --chown=pause app_2017.psgi app_2017.psgi + +CMD ["plackup","app_2017.psgi"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..7a7ef63df --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,67 @@ +services: + pause: &pause + build: + context: ./ + dockerfile: Containerfile + ports: + - 5000:5000 + volumes: + - ./docker-compose/PrivatePAUSE.pm:/home/pause/privatelib/PrivatePAUSE.pm + - ./docker-compose/tmp:/pause-run/tmp + - ./lib:/home/pause/lib + - ./bin:/home/pause/bin + - pause_run:/pause-run + - pause_data:/data + environment: + PAUSE_DEV_ROOT: /home/pause + PAUSE_DEV_EMAIL: pause@localhost.localdomain + PAUSE_DEV_DBUSER: pause + PAUSE_DEV_DBPASS: test + EMAIL_SENDER_TRANSPORT: SMTP + EMAIL_SENDER_TRANSPORT_host: mail + EMAIL_SENDER_TRANSPORT_port: 1025 + depends_on: + - mysql + - mail + command: plackup -p 5000 -R /home/pause/lib/pause_2017 app_2017.psgi + paused: + <<: *pause + ports: [] + command: bin/paused --pidfile /pause-run/pid/paused.pid + mysql: + image: mysql:5.7 + container_name: mysql + volumes: + - ./doc/mod.schema.txt:/docker-entrypoint-initdb.d/01_mod.schema.sql + - ./doc/authen_pause.schema.txt:/docker-entrypoint-initdb.d/02_authen_pause.schema.sql + - ./docker-compose/mysql/03_fixtures.sql:/docker-entrypoint-initdb.d/03_fixtures.sql + - mysql_db:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: test + MYSQL_USER: pause + MYSQL_PASSWORD: test + MYSQL_DATABASE: pause + expose: + - 3306 + mail: + image: axllent/mailpit + ports: + - 1025:1025 + - 8025:8025 + environment: + MP_MAX_MESSAGES: 100 + MP_SMTP_AUTH_ACCEPT_ANY: 1 + MP_SMTP_AUTH_ALLOW_INSECURE: 1 + nginx: + image: nginx:latest + ports: + - 8080:8080 + depends_on: + - pause + volumes: + - ./htdocs:/var/www/html/ + - ./docker-compose/nginx/default.conf:/etc/nginx/conf.d/default.conf +volumes: + mysql_db: + pause_run: + pause_data: diff --git a/docker-compose/PrivatePAUSE.pm b/docker-compose/PrivatePAUSE.pm new file mode 100644 index 000000000..f519b1489 --- /dev/null +++ b/docker-compose/PrivatePAUSE.pm @@ -0,0 +1,52 @@ +package PrivatePAUSE; +use File::Spec::Functions qw(catdir catfile); +use Email::Sender::Simple; + +my $Root = $ENV{PAUSE_DEV_ROOT} // '/home/pause'; +my $Email = $ENV{PAUSE_DEV_EMAIL} // 'pause@localhost.localdomain'; + +print STDERR "ENV: $_: $ENV{$_}\n" for sort keys %ENV; + +print STDERR "Root: $Root\n"; +print STDERR "Email: $Email\n"; + +$PAUSE::Config->{AUTHEN_DATA_SOURCE_NAME} = 'dbi:mysql:pause;host=mysql'; +$PAUSE::Config->{AUTHEN_DATA_SOURCE_USER} = 'pause'; +$PAUSE::Config->{AUTHEN_DATA_SOURCE_PW} = 'test'; + +$PAUSE::Config->{MOD_DATA_SOURCE_NAME} = 'dbi:mysql:pause;host=mysql'; +$PAUSE::Config->{MOD_DATA_SOURCE_USER} = 'pause'; +$PAUSE::Config->{MOD_DATA_SOURCE_PW} = 'test'; + +$PAUSE::Config->{DOCUMENT_ROOT} = catdir($Root, 'htdocs'); +$PAUSE::Config->{ADMIN} = $Email; +$PAUSE::Config->{ADMINS} = [$Email]; +$PAUSE::Config->{CPAN_TESTERS} = $Email; +$PAUSE::Config->{TO_CPAN_TESTERS} = $Email; +$PAUSE::Config->{REPLY_TO_CPAN_TESTERS} = $Email; +$PAUSE::Config->{GONERS_NOTIFY} = $Email; +$PAUSE::Config->{P5P} = $Email; +$PAUSE::Config->{ML_CHOWN_USER} = 'nobody'; +$PAUSE::Config->{ML_CHOWN_GROUP} = 'nogroup'; +$PAUSE::Config->{ML_MIN_INDEX_LINES} = 0; +$PAUSE::Config->{ML_MIN_FILES} = 0; +$PAUSE::Config->{RUNDATA} = '/pause-run/rundata'; +$PAUSE::Config->{UPLOAD} = $Email; +$PAUSE::Config->{HAVE_PERLBAL} = 0; +$PAUSE::Config->{SLEEP} = 1; +$PAUSE::Config->{PAUSE_LOG} = '/pause-run/log/paused.log'; +$PAUSE::Config->{PAUSE_LOG_DIR} = '/pause-run/log/'; +$PAUSE::Config->{INCOMING} = 'file://data/pause/incoming/'; +$PAUSE::Config->{RECAPTCHA_ENABLED} = 1 unless $ENV{TEST_HARNESS}; +$PAUSE::Config->{CHECKSUMS_SIGNING_ARGS} = '--homedir /root/.gnupg --clearsign --default-key'; +$PAUSE::Config->{CHECKSUMS_SIGNING_KEY} = 'A34B1DABBB49489C'; +$PAUSE::Config->{BATCH_SIG_HOME} = '/root/.gnupg'; + +$PAUSE::Config->{TESTHOST_SCHEMA} = 'http'; +$PAUSE::Config->{CRONPATH} = '/home/pause/cron'; + +$PAUSE::Config->{SKIP_GIT} = 1; +$PAUSE::Config->{CHECKSUMS_SIGNING_PROGRAM} = 'false'; + +1; + diff --git a/docker-compose/mysql/03_fixtures.sql b/docker-compose/mysql/03_fixtures.sql new file mode 100644 index 000000000..6f39b4d46 --- /dev/null +++ b/docker-compose/mysql/03_fixtures.sql @@ -0,0 +1,6 @@ +INSERT INTO `grouptable` VALUES ('TESTADMIN','admin'); + +INSERT INTO `users` VALUES ('TESTADMIN','unused','1970-01-01 00:00:00','testadmin@localhost','secr','','TESTADMIN Name',NULL,'',NULL,NULL,''),('TESTCNSRD','unused','1970-01-01 00:00:00','CENSORED','secr','','TESTCNSRD Name',NULL,'',NULL,NULL,''),('TESTUSER','unused','1970-01-01 00:00:00','testuser@localhost','secr','','TESTUSER Name',NULL,'',NULL,NULL,''); + +INSERT INTO `usertable` VALUES ('TESTADMIN','$2a$12$CoQEZPZVEzqlkQWPzzQTses.eK86BVM07tjtWCywrPGnbLsc/0eTC','testadmin@localhost',0,NULL,NULL,NULL),('TESTCNSRD','$2a$12$zV/qZSD4Oa6uB4onl0b/6uA0yrcELZWebBCZOeX0T9rlmD97qXWj6','testcnsrd@localhost',0,NULL,NULL,NULL),('TESTUSER','$2a$12$Xq5nX/5AI4y/lbPC/wHbIeTpGXY76u8F8go90i03umhwRpG0bjtG2','testuser@localhost',0,NULL,NULL,NULL); + diff --git a/docker-compose/nginx/default.conf b/docker-compose/nginx/default.conf new file mode 100644 index 000000000..04e83a47e --- /dev/null +++ b/docker-compose/nginx/default.conf @@ -0,0 +1,46 @@ +upstream psgi { + server pause:5000; +} + +server { + listen 8080; + listen [::]:8080; + server_name pause.localhost; + + root /var/www/html; + + location ~ /pause/.*\.(js|css|jpg|gif|png) { + expires 7d; + break; + } + + location /incoming/ { + root /home/ftp; + autoindex on; + autoindex_exact_size off; + autoindex_localtime on; + } + + location /pub/ { + root /home/ftp; + autoindex on; + autoindex_exact_size off; + autoindex_localtime on; + } + + location / { + proxy_pass http://psgi; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_pass_request_headers on; + proxy_no_cache $cookie_nocache $arg_nocache$arg_comment; + proxy_no_cache $http_pragma $http_authorization; + proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment; + proxy_cache_bypass $http_pragma $http_authorization; + proxy_pass_header Authorization; + } +} diff --git a/docker-compose/setup.sh b/docker-compose/setup.sh new file mode 100755 index 000000000..1fbcc8d66 --- /dev/null +++ b/docker-compose/setup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +mkdir -p \ + /pause-run/tmp \ + /pause-run/pid \ + /pause-run/log \ + /pause-run/rundata/session + +mkdir -p \ + /data/pause/ftp \ + /data/pause/tmp \ + /data/pause/incoming \ + /data/pause/pub/PAUSE/PAUSE-git \ + /data/pause/pub/PAUSE/PAUSE-data \ + /data/pause/pub/PAUSE/modules \ + /data/pause/pub/PAUSE/authors/id + +chown -R pause: /pause-run +chown -R pause: /data + diff --git a/docker-compose/tmp/readme b/docker-compose/tmp/readme new file mode 100644 index 000000000..2fcec6902 --- /dev/null +++ b/docker-compose/tmp/readme @@ -0,0 +1 @@ +placeholder so we can track this file in git From 5c85401d3a6f8cf7d0f22278c87b0ac7f33d4b62 Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Sun, 26 Apr 2026 16:02:32 +0200 Subject: [PATCH 2/3] document local dev setup using docker-compose --- doc/local-dev-docker-compose.md | 116 ++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 doc/local-dev-docker-compose.md diff --git a/doc/local-dev-docker-compose.md b/doc/local-dev-docker-compose.md new file mode 100644 index 000000000..440e3c368 --- /dev/null +++ b/doc/local-dev-docker-compose.md @@ -0,0 +1,116 @@ + +# Local development using docker-compose + +To make local development easier, we now provide a container based setup orchestrated using `docker compose`. This setup is for local development only, **do not** use it for a production or even staging environment! + +## Prerequisites + +You will need: + +* docker with `docker compose` + +## Overview + +* `docker compose up` +* Go to `http://pause.localhost:8080` +* Login with userid `testuser`, password `test` +* Play around with it! +* Read mail sent by pause at `http://localhost:8025` +* `docker compose down` + +The setup will persist after `docker compose down`. + +## Running + +### Start + +To start the whole stack, do + +`docker compose up` + +This should fetch or build the required containers, set up an empty database and start the web app (`pause`) and `paused`. + +If you have changed the `Containerfile` or `cpanfile`, rebuild the image first: + +`docker compose up --build` + +To see less output, list the specific services you want to see, eg + +`docker compose up pause paused` + +### Access the container(s) + +* If the container is already running (started via `up`): + * `docker compose exec {{container-name}} {{comand}}` + * eg `docker compose exec pause bash` +* If it is not running: + * `docker compose run --rm -ti {{container-name}} {{command}}` + * `docker compose run --rm -ti paused cat /etc/passwd` + +To inspect files inside the container, access the container and look around there. + +To copy files from the container to the host (eg for more detailed analysis), copy it to `/pause-run/tmp`, which is mounted to `docker-compose/tmp/`: + +``` +~/perl/pause$ d-c exec pause bash +pause@bb2bd8edaad0:~$ echo "Hello" > /pause-run/tmp/foo +pause@bb2bd8edaad0:~$ exit +~/perl/pause$ ls docker-compose/tmp/ +foo +``` + +### Stop + +`docker compose down` + +### Resetting + +The current setup persists data between restarts. This applies to the DB and to files stored in `/data/pause` and `/pause-run`. + +To reset those files (for a complete fresh start), do: + +``` +docker compose stop +docker compose down +docker volume rm pause_mysql_db # deletes the database +docker volume rm pause_pause_data # deletes /data +docker volume rm pause_pause_run # deletes /pause-run +``` + +The next `docker compose up` will set up a fresh database and empty directories. + +## Services + +### pause + +The `pause` Plack app (currently `app_2017`) providing the web interface. Runs on port 5000 inside the container. But you should use the `nginx` proxy (see below). + +### paused + +The pause daemon handling uploads. Logs to `/pause-run/log/paused.log`. + +To tail the log from the host, do: + +`docker compose exec paused tail -f /pause-run/log/paused.log` + +### mysql + +The mysql database server. It contains the pause schema, 3 test users, but no further data. Data will persist between restart of the service. + +To connect to the database from the host, do: + +`docker compose exec mysql mysql -uroot -ptest pause` + +To reset the DB, stop all services (`docker compose down`) and delete the volume: + +`docker volume rm pause_mysql_db` + +### nginx + +A nginx frontend proxy. Currently only for serving static files, but could be used in the future to terminate some semi-fake SSL for testing. + +### mail + +An instance of [mailpit](https://mailpit.axllent.org/). This is a combined SMTP server (listening on port 1025 for incoming email) and webmail (on port 8025). `pause` can send email to `mailpit`, and you can read the mail on `http://localhost:8025`. No mail will actually leave your system! + + From eaf8837a3fb565cf21b070346446dbee6c34659b Mon Sep 17 00:00:00 2001 From: Thomas Klausner Date: Sun, 26 Apr 2026 16:22:28 +0200 Subject: [PATCH 3/3] enable pause-2026, use cpm --- Containerfile | 5 +++-- doc/local-dev-docker-compose.md | 7 ++++--- docker-compose.yml | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Containerfile b/Containerfile index cd8e48428..8f1cb5c7c 100644 --- a/Containerfile +++ b/Containerfile @@ -9,7 +9,7 @@ RUN useradd -m --shell /bin/bash pause WORKDIR /home/pause COPY cpanfile cpanfile -RUN cpanm -n --installdeps . +RUN cpm install -g COPY docker-compose/setup.sh /setup.sh RUN /setup.sh @@ -24,5 +24,6 @@ COPY --chown=pause cron cron COPY --chown=pause bin bin COPY --chown=pause lib lib COPY --chown=pause app_2017.psgi app_2017.psgi +COPY --chown=pause app_2026.psgi app_2026.psgi -CMD ["plackup","app_2017.psgi"] +CMD ["plackup","app_2026.psgi"] diff --git a/doc/local-dev-docker-compose.md b/doc/local-dev-docker-compose.md index 440e3c368..c98326997 100644 --- a/doc/local-dev-docker-compose.md +++ b/doc/local-dev-docker-compose.md @@ -13,9 +13,10 @@ You will need: * `docker compose up` * Go to `http://pause.localhost:8080` + * It might happen that your browser redirects to `https://pause.localhost:8080`, which won't work. If this happens, adjust the protocol in the browser address bar and reload. * Login with userid `testuser`, password `test` * Play around with it! -* Read mail sent by pause at `http://localhost:8025` +* Read mail sent by PAUSE at `http://localhost:8025` * `docker compose down` The setup will persist after `docker compose down`. @@ -87,7 +88,7 @@ The `pause` Plack app (currently `app_2017`) providing the web interface. Runs o ### paused -The pause daemon handling uploads. Logs to `/pause-run/log/paused.log`. +The PAUSE daemon handling uploads. Logs to `/pause-run/log/paused.log`. To tail the log from the host, do: @@ -95,7 +96,7 @@ To tail the log from the host, do: ### mysql -The mysql database server. It contains the pause schema, 3 test users, but no further data. Data will persist between restart of the service. +The mysql database server. It contains the PAUSE schema, 3 test users, but no further data. Data will persist between restart of the service. To connect to the database from the host, do: diff --git a/docker-compose.yml b/docker-compose.yml index 7a7ef63df..48e973d35 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,7 +23,7 @@ services: depends_on: - mysql - mail - command: plackup -p 5000 -R /home/pause/lib/pause_2017 app_2017.psgi + command: plackup -p 5000 -R /home/pause/lib/pause_2026 app_2026.psgi paused: <<: *pause ports: []