diff --git a/.circleci/config.yml b/.circleci/config.yml index c2aaaa5..873f4a7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ jobs: type: string default: "no" machine: - image: ubuntu-2004:202010-01 + image: default environment: DOCKER_BUILDKIT: 1 BUILDKIT_PROGRESS: plain @@ -37,11 +37,16 @@ jobs: DB: mysql name: MySQL Test command: bash tests/test.sh - - deploy: - name: Deploy + - run: + name: Run version command: | python3 --version python3 deploy.py + - store_artifacts: + path: /opt/mailman/web/logs/ + + - store_artifacts: + path: /opt/mailman/core/var/logs workflows: version: 2 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..50043f6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,34 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "docker" # See documentation for possible values + directory: "/core" # Location of package manifests + schedule: + interval: "weekly" + - package-ecosystem: "docker" # See documentation for possible values + directory: "/web" # Location of package manifests + schedule: + interval: "weekly" + - package-ecosystem: "docker" # See documentation for possible values + directory: "/postorius" # Location of package manifests + schedule: + interval: "weekly" + # Enable version updates for Actions + - package-ecosystem: "github-actions" + # Look for `.github/workflows` in the `root` directory + directory: "/" + # Check for updates once a week + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/core" + schedule: + interval: "daily" + - package-ecosystem: "pip" + directory: "/web" + schedule: + interval: "daily" \ No newline at end of file diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index 2d202e6..856a7d0 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout main - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Deploy docs uses: mhausenblas/mkdocs-deploy-gh-pages@master diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..bc81445 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,28 @@ +# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. +# +# You can adjust the behavior by modifying this file. +# For more information, see: +# https://github.com/actions/stale +name: Mark stale issues and pull requests + +on: + schedule: + - cron: '19 22 * * *' + +jobs: + stale: + + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue has not been updated for more than 1year' + stale-pr-message: 'This Pull Request has not been updated for more than 1year' + stale-issue-label: 'no-issue-activity' + stale-pr-label: 'no-pr-activity' + days-before-stale: 365 diff --git a/README.md b/README.md index d67df98..c5988de 100644 --- a/README.md +++ b/README.md @@ -54,25 +54,21 @@ Releases will follow the following rules: ## Container Registries - -The container images are available from multiple container registries: +The container images are available from multiple container registries. Do specify an [explicit version tag](https://hub.docker.com/r/maxking/mailman-web/tags?page=1&ordering=last_updated&name=0.) (e.g. `0.4.5` , MAJOR.MINOR like `0.4` also works as floating tag pointing to latest patch version) as tag `latest` is **not** updated anymore. ### Mailman Core - `ghcr.io/maxking/mailman-core` -- `quay.io/maxking/mailman-core` - `docker.io/maxking/mailman-core` ### Mailman Web - `ghcr.io/maxking/mailman-web` -- `quay.io/maxking/mailman-web` - `docker.io/maxking/mailman-web` ### Postorius - `ghcr.io/maxking/postorius` -- `quay.io/maxking/postorius` - `docker.io/maxking/postorius` ## Rolling Releases @@ -214,6 +210,10 @@ These are the variables that you MUST change in your docker-compose.yaml before - `DATABASE_CLASS`: Default value is `mailman.database.sqlite.SQLiteDatabase`. The values for this can be found in the mailman's documentation [here][11]. +- `SMTP_HOST` : outgoing host for SMTP connections +- `SMTP_PORT` : use this port. 25, 587, whatever your host asks for. +- `SMTP_HOST_USER`: authenticate this user +- `SMTP_HOST_PASSWORD`: and use this password For more details on how to configure this image, please look [Mailman-core's Readme](core/) diff --git a/core/Dockerfile b/core/Dockerfile index ca904e6..65a13e0 100644 --- a/core/Dockerfile +++ b/core/Dockerfile @@ -1,26 +1,30 @@ # syntax = docker/dockerfile:1.3 -FROM alpine:3.12 +# Use 3.15 for Core since it has Python 3.9 +FROM alpine:3.19 -#Add startup script to container -COPY docker-entrypoint.sh /usr/local/bin/ +# Add requirements file. +COPY requirements.txt /tmp/ #Install all required packages, add user for executing mailman and set execution rights for startup script RUN --mount=type=cache,target=/root/.cache \ apk update \ && apk add --virtual build-deps gcc python3-dev musl-dev postgresql-dev \ libffi-dev \ + # Mailman html to plaintext conversion uses lynx. # psutil needs linux-headers to compile on musl c library. - && apk add --no-cache bash su-exec postgresql-client mysql-client curl python3 py3-pip linux-headers py-cryptography mariadb-connector-c \ - && python3 -m pip install -U pip setuptools wheel \ - && python3 -m pip install psycopg2 \ + && apk add --no-cache bash su-exec postgresql-client mysql-client curl python3 py3-pip linux-headers py-cryptography mariadb-connector-c lynx tzdata \ + && python3 -m pip install --break-system-packages -U pip setuptools wheel \ + && python3 -m pip install --break-system-packages psycopg2 \ gunicorn==19.9.0 \ - mailman==3.3.5 \ - mailman-hyperkitty==1.2.0 \ pymysql \ - 'sqlalchemy<1.4.0' \ + -r /tmp/requirements.txt \ + 'importlib-resources<6.0.0' \ && apk del build-deps \ && adduser -S mailman +#Add startup script to container +COPY docker-entrypoint.sh /usr/local/bin/ + # Change the working directory. WORKDIR /opt/mailman diff --git a/core/Dockerfile.dev b/core/Dockerfile.dev index bb0c0b8..7064e34 100644 --- a/core/Dockerfile.dev +++ b/core/Dockerfile.dev @@ -1,29 +1,30 @@ # syntax = docker/dockerfile:1.3 -FROM alpine:3.12 - -#Add startup script to container -COPY docker-entrypoint.sh /usr/local/bin/ +# Use 3.15 for Core since it has Python 3.9 +FROM alpine:3.19 # Set the commits that we are building. ARG CORE_REF ARG MM3_HK_REF - #Install all required packages, add user for executing mailman and set execution #rights for startup script RUN --mount=type=cache,target=/root/.cache \ apk update \ && apk add --no-cache --virtual build-deps gcc python3-dev musl-dev \ - postgresql-dev git libffi-dev \ - && apk add --no-cache bash su-exec postgresql-client mysql-client curl python3 py3-pip linux-headers py-cryptography mariadb-connector-c \ - && python3 -m pip install -U psycopg2 pymysql setuptools wheel \ - && python3 -m pip install \ + postgresql-dev git libffi-dev g++ \ + && apk add --no-cache bash su-exec postgresql-client mysql-client \ + curl python3 py3-pip linux-headers py-cryptography mariadb-connector-c tzdata \ + && python3 -m pip install -U --break-system-packages psycopg2 pymysql setuptools wheel \ + && python3 -m pip install --break-system-packages \ git+https://gitlab.com/mailman/mailman \ git+https://gitlab.com/mailman/mailman-hyperkitty \ gunicorn==19.9.0 \ && apk del build-deps \ && adduser -S mailman +#Add startup script to container +COPY docker-entrypoint.sh /usr/local/bin/ + # Change the working directory. WORKDIR /opt/mailman diff --git a/core/docker-entrypoint.sh b/core/docker-entrypoint.sh index 80aa6c7..d0bd089 100755 --- a/core/docker-entrypoint.sh +++ b/core/docker-entrypoint.sh @@ -6,7 +6,7 @@ function wait_for_postgres () { # moving forward. # TODO: Use python3's psycopg2 module to do this in python3 instead of # installing postgres-client in the image. - until psql $DATABASE_URL -c '\l'; do + until psql -P pager=off $DATABASE_URL -c '\l'; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done @@ -67,7 +67,7 @@ function setup_database () { # Translate mysql:// urls to mysql+mysql:// backend: if [[ "$DATABASE_URL" == mysql://* ]]; then DATABASE_URL="mysql+pymysql://${DATABASE_URL:8}" - echo "Database URL was automatically rewritten to: $DATABASE_URL" + echo "Database URL prefix was automatically rewritten to: mysql+pymysql://" fi # If DATABASE_CLASS is not set, guess it for common databases: @@ -142,6 +142,8 @@ lmtp_host: $MM_HOSTNAME lmtp_port: 8024 smtp_host: $SMTP_HOST smtp_port: $SMTP_PORT +smtp_user: $SMTP_HOST_USER +smtp_pass: $SMTP_HOST_PASSWORD configuration: python:mailman.config.exim4 EOF @@ -163,6 +165,8 @@ lmtp_host: $MM_HOSTNAME lmtp_port: 8024 smtp_host: $SMTP_HOST smtp_port: $SMTP_PORT +smtp_user: $SMTP_HOST_USER +smtp_pass: $SMTP_HOST_PASSWORD configuration: /etc/postfix-mailman.cfg EOF diff --git a/core/requirements.txt b/core/requirements.txt new file mode 100644 index 0000000..b100b91 --- /dev/null +++ b/core/requirements.txt @@ -0,0 +1,5 @@ +# This is a separate file from Dockerfile so that we can use dependabot +# for version updates that isn't supported for contents inside the +# Dockerfile. +mailman==3.3.9 +mailman-hyperkitty==1.2.1 \ No newline at end of file diff --git a/docker-compose-mysql.yaml b/docker-compose-mysql.yaml index 5d8358e..78f0cf1 100644 --- a/docker-compose-mysql.yaml +++ b/docker-compose-mysql.yaml @@ -2,9 +2,10 @@ version: '2' services: mailman-core: - image: maxking/mailman-core:0.4 + image: maxking/mailman-core:0.4 # Use a specific version tag (tag latest is not published) container_name: mailman-core hostname: mailman-core + restart: unless-stopped volumes: - /opt/mailman/core:/opt/mailman/ stop_grace_period: 30s @@ -13,9 +14,8 @@ services: depends_on: - database environment: - - DATABASE_URL=mysql+pymysql://mailman:mailmanpass@database/mailmandb?charset=utf8mb4&use_unicode=1 + - DATABASE_URL=mysql+pymysql://mailman:mailmanpass@database/mailmandb?charset=utf8mb4&use_unicode=1 # Do use mysql+pymysql:// here - DATABASE_TYPE=mysql - - DATABASE_CLASS=mailman.database.mysql.MySQLDatabase - HYPERKITTY_API_KEY=someapikey ports: - "127.0.0.1:8001:8001" # API @@ -24,9 +24,10 @@ services: mailman: mailman-web: - image: maxking/mailman-web:0.4 + image: maxking/mailman-web:0.4 # Use a specific version tag (tag latest is not published) container_name: mailman-web hostname: mailman-web + restart: unless-stopped depends_on: - database links: @@ -36,7 +37,7 @@ services: - /opt/mailman/web:/opt/mailman-web-data environment: - DATABASE_TYPE=mysql - - DATABASE_URL=mysql://mailman:mailmanpass@database/mailmandb?charset=utf8mb4 + - DATABASE_URL=mysql://mailman:mailmanpass@database/mailmandb?charset=utf8mb4 # Do use mysql:// here - HYPERKITTY_API_KEY=someapikey - SECRET_KEY=thisisaverysecretkey - DYLD_LIBRARY_PATH=/usr/local/mysql/lib/ @@ -66,4 +67,4 @@ networks: driver: default config: - - subnet: 172.19.199.0/24 \ No newline at end of file + subnet: 172.19.199.0/24 diff --git a/docker-compose-postorius.yaml b/docker-compose-postorius.yaml index 64f0af2..4e733cf 100644 --- a/docker-compose-postorius.yaml +++ b/docker-compose-postorius.yaml @@ -2,9 +2,10 @@ version: '2' services: mailman-core: - image: maxking/mailman-core:0.4 + image: maxking/mailman-core:0.4 # Use a specific version tag (tag latest is not published) container_name: mailman-core hostname: mailman-core + restart: unless-stopped volumes: - /opt/mailman/core:/opt/mailman/ stop_grace_period: 30s @@ -23,9 +24,10 @@ services: mailman: mailman-web: - image: maxking/postorius:0.4 + image: maxking/postorius:0.4 # Use a specific version tag (tag latest is not published) container_name: mailman-web hostname: mailman-web + restart: unless-stopped depends_on: - database links: @@ -63,4 +65,4 @@ networks: driver: default config: - - subnet: 172.19.199.0/24 \ No newline at end of file + subnet: 172.19.199.0/24 diff --git a/docker-compose.yaml b/docker-compose.yaml index 5390bf1..b23fdb0 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -2,9 +2,10 @@ version: '2' services: mailman-core: - image: maxking/mailman-core:0.4 + image: maxking/mailman-core:0.4 # Use a specific version tag (tag latest is not published) container_name: mailman-core hostname: mailman-core + restart: unless-stopped volumes: - /opt/mailman/core:/opt/mailman/ stop_grace_period: 30s @@ -13,7 +14,7 @@ services: depends_on: - database environment: - - DATABASE_URL=postgres://mailman:mailmanpass@database/mailmandb + - DATABASE_URL=postgresql://mailman:mailmanpass@database/mailmandb - DATABASE_TYPE=postgres - DATABASE_CLASS=mailman.database.postgresql.PostgreSQLDatabase - HYPERKITTY_API_KEY=someapikey @@ -24,9 +25,10 @@ services: mailman: mailman-web: - image: maxking/mailman-web:0.4 + image: maxking/mailman-web:0.4 # Use a specific version tag (tag latest is not published) container_name: mailman-web hostname: mailman-web + restart: unless-stopped depends_on: - database links: @@ -36,7 +38,7 @@ services: - /opt/mailman/web:/opt/mailman-web-data environment: - DATABASE_TYPE=postgres - - DATABASE_URL=postgres://mailman:mailmanpass@database/mailmandb + - DATABASE_URL=postgresql://mailman:mailmanpass@database/mailmandb - HYPERKITTY_API_KEY=someapikey ports: - "127.0.0.1:8000:8000" # HTTP @@ -49,7 +51,7 @@ services: - POSTGRES_DB=mailmandb - POSTGRES_USER=mailman - POSTGRES_PASSWORD=mailmanpass - image: postgres:9.6-alpine + image: postgres:12-alpine volumes: - /opt/mailman/database:/var/lib/postgresql/data networks: @@ -62,4 +64,4 @@ networks: driver: default config: - - subnet: 172.19.199.0/24 \ No newline at end of file + subnet: 172.19.199.0/24 diff --git a/postorius/Dockerfile b/postorius/Dockerfile index 408c832..93eaca8 100644 --- a/postorius/Dockerfile +++ b/postorius/Dockerfile @@ -1,34 +1,36 @@ # syntax = docker/dockerfile:1.3 -FROM alpine:3.12 - -# Add needed files for uwsgi server + settings for django -COPY mailman-web /opt/mailman-web -# Add startup script to container -COPY docker-entrypoint.sh /usr/local/bin/ +FROM alpine:3.20.0 # Install packages and dependencies for postorius and hyperkitty Add user for # executing apps, change ownership for uwsgi+django files and set execution # rights for management script RUN --mount=type=cache,target=/root/.cache \ set -ex \ - && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers \ + && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers libldap \ postgresql-dev mariadb-dev mariadb-connector-c python3-dev libffi-dev openldap-dev cargo rust \ - && apk add --no-cache --virtual .mailman-rundeps bash sassc \ + && apk add --no-cache --virtual .mailman-rundeps bash sassc tzdata \ postgresql-client mysql-client py3-mysqlclient curl mailcap gettext \ python3 py3-pip libffi libuuid pcre-dev py-cryptography \ - && python3 -m pip install -U 'Django<3.2' pip setuptools wheel \ - && python3 -m pip install postorius==1.3.6 \ + && python3 -m pip install --break-system-packages -U 'Django<4.3' pip setuptools wheel \ + && python3 -m pip install --break-system-packages postorius==1.3.10 \ uwsgi \ - 'psycopg2<2.9' \ + psycopg2 \ dj-database-url \ mysqlclient \ typing \ django-auth-ldap \ python-memcached \ + tzdata \ && apk del .build-deps \ && addgroup -S mailman \ - && adduser -S -G mailman mailman \ - && chown -R mailman /opt/mailman-web/ \ + && adduser -S -G mailman mailman + +# Add needed files for uwsgi server + settings for django +COPY mailman-web /opt/mailman-web +# Add startup script to container +COPY docker-entrypoint.sh /usr/local/bin/ + +RUN chown -R mailman /opt/mailman-web/ \ && chmod u+x /opt/mailman-web/manage.py WORKDIR /opt/mailman-web diff --git a/postorius/Dockerfile.dev b/postorius/Dockerfile.dev index e427a1c..b80a66c 100644 --- a/postorius/Dockerfile.dev +++ b/postorius/Dockerfile.dev @@ -1,10 +1,5 @@ # syntax = docker/dockerfile:1.3 -FROM alpine:3.12 - -# Add needed files for uwsgi server + settings for django -COPY mailman-web /opt/mailman-web -# Add startup script to container -COPY docker-entrypoint.sh /usr/local/bin/ +FROM alpine:3.20.0 ARG POSTORIUS_REF ARG DJ_MM3_REF @@ -15,28 +10,34 @@ ARG CLIENT_REF # rights for management script RUN --mount=type=cache,target=/root/.cache \ set -ex \ - && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers \ + && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers libldap \ postgresql-dev mariadb-dev mariadb-connector-c python3-dev libffi-dev git cargo rust \ - && apk add --no-cache --virtual .mailman-rundeps bash sassc \ + && apk add --no-cache --virtual .mailman-rundeps bash sassc tzdata \ postgresql-client mysql-client py3-mysqlclient curl mailcap \ python3 py3-pip libffi gettext py-cryptography \ - && python3 -m pip install -U pip setuptools wheel \ - && python3 -m pip install -U \ + && python3 -m pip install --break-system-packages -U pip setuptools wheel \ + && python3 -m pip install --break-system-packages -U \ git+https://gitlab.com/mailman/mailmanclient \ git+https://gitlab.com/mailman/postorius \ uwsgi \ - 'psycopg2<2.9' \ + psycopg2 \ dj-database-url \ mysqlclient \ typing \ django-utils-six \ - && python3 -m pip install -U 'Django<3.2' \ - && python3 -m pip install -U \ + && python3 -m pip install --break-system-packages -U 'Django<4.3' \ + && python3 -m pip install --break-system-packages -U \ git+https://gitlab.com/mailman/django-mailman3 \ && apk del .build-deps \ && addgroup -S mailman \ - && adduser -S -G mailman mailman \ - && chown -R mailman /opt/mailman-web/ \ + && adduser -S -G mailman mailman + +# Add needed files for uwsgi server + settings for django +COPY mailman-web /opt/mailman-web +# Add startup script to container +COPY docker-entrypoint.sh /usr/local/bin/ + +RUN chown -R mailman /opt/mailman-web/ \ && chmod u+x /opt/mailman-web/manage.py WORKDIR /opt/mailman-web diff --git a/postorius/docker-entrypoint.sh b/postorius/docker-entrypoint.sh index eef042c..eeca683 100755 --- a/postorius/docker-entrypoint.sh +++ b/postorius/docker-entrypoint.sh @@ -7,7 +7,7 @@ function wait_for_postgres () { # moving forward. # TODO: Use python's psycopg2 module to do this in python instead of # installing postgres-client in the image. - until psql $DATABASE_URL -c '\l'; do + until psql -P pager=off $DATABASE_URL -c '\l'; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done diff --git a/postorius/mailman-web/settings.py b/postorius/mailman-web/settings.py index d701c4e..ab10f2b 100644 --- a/postorius/mailman-web/settings.py +++ b/postorius/mailman-web/settings.py @@ -46,16 +46,14 @@ ADMINS = ( SITE_ID = 1 # Hosts/domain names that are valid for this site; required if DEBUG is False -# See https://docs.djangoproject.com/en/1.8/ref/settings/#allowed-hosts +# See https://docs.djangoproject.com/en/3.1/ref/settings/#allowed-hosts ALLOWED_HOSTS = [ "localhost", # Archiving API from Mailman, keep it. - # "lists.your-domain.org", - # Add here all production URLs you may have. "mailman-web", gethostbyname("mailman-web"), os.environ.get('SERVE_FROM_DOMAIN'), - os.environ.get('DJANGO_ALLOWED_HOSTS'), ] +ALLOWED_HOSTS.extend(os.getenv("DJANGO_ALLOWED_HOSTS", "").split(",")) # Mailman API credentials MAILMAN_REST_API_URL = os.environ.get('MAILMAN_REST_URL', 'http://mailman-core:8001') @@ -78,6 +76,7 @@ DEFAULT_APPS = [ 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.humanize', 'django_gravatar', 'allauth', 'allauth.account', @@ -101,6 +100,7 @@ MIDDLEWARE = ( 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django_mailman3.middleware.TimezoneMiddleware', + 'allauth.account.middleware.AccountMiddleware', 'postorius.middleware.PostoriusMiddleware', ) @@ -143,6 +143,11 @@ DATABASES = { 'default': dj_database_url.config(conn_max_age=600) } +# Avoid Django 3.2+ warning +# https://github.com/maxking/docker-mailman/issues/595 +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + + # If you're behind a proxy, use the X-Forwarded-Host header # See https://docs.djangoproject.com/en/1.8/ref/settings/#use-x-forwarded-host USE_X_FORWARDED_HOST = True diff --git a/postorius/mailman-web/urls.py b/postorius/mailman-web/urls.py index 804b9e3..3e3c312 100644 --- a/postorius/mailman-web/urls.py +++ b/postorius/mailman-web/urls.py @@ -16,19 +16,18 @@ # You should have received a copy of the GNU General Public License along with # Postorius. If not, see . - -from django.conf.urls import include, url +from django.conf.urls import include from django.contrib import admin -from django.urls import reverse_lazy +from django.urls import re_path, reverse_lazy from django.views.generic import RedirectView urlpatterns = [ - url(r'^$', RedirectView.as_view( + re_path(r'^$', RedirectView.as_view( url=reverse_lazy('list_index'), permanent=True)), - url(r'^postorius/', include('postorius.urls')), - url(r'', include('django_mailman3.urls')), - url(r'^accounts/', include('allauth.urls')), + re_path(r'postorius/', include('postorius.urls')), + re_path(r'', include('django_mailman3.urls')), + re_path(r'accounts/', include('allauth.urls')), # Django admin - url(r'^admin/', admin.site.urls), + re_path(r'^admin/', admin.site.urls), ] diff --git a/postorius/mailman-web/uwsgi.ini b/postorius/mailman-web/uwsgi.ini index 9c025ee..e5d00a6 100644 --- a/postorius/mailman-web/uwsgi.ini +++ b/postorius/mailman-web/uwsgi.ini @@ -3,7 +3,7 @@ uwsgi-socket = 0.0.0.0:8080 http-socket = 0.0.0.0:8000 -# Move to the directory wher the django files are. +# Move to the directory where the django files are. chdir = /opt/mailman-web # Use the wsgi file provided with the django project. @@ -14,7 +14,7 @@ master = true processes = 2 threads = 2 -# Drop privielges and don't run as root. +# Drop privileges and don't run as root. uid = mailman gid = mailman diff --git a/tests/docker-test.yaml b/tests/docker-test.yaml index 950bbf3..2911cfe 100644 --- a/tests/docker-test.yaml +++ b/tests/docker-test.yaml @@ -8,3 +8,4 @@ services: image: maxking/mailman-web:rolling environment: - SECRET_KEY=abcdefghijklmnopqrstuv + - SERVE_FROM_DOMAIN=araj.me diff --git a/web/Dockerfile b/web/Dockerfile index 297f074..2c2f464 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -1,42 +1,44 @@ # syntax = docker/dockerfile:1.3 -FROM alpine:3.12 +FROM alpine:3.20.0 -# Add needed files for uwsgi server + settings for django -COPY mailman-web /opt/mailman-web -# Add startup script to container -COPY docker-entrypoint.sh /usr/local/bin/ +# Add requirements file. +COPY requirements.txt /tmp/ # Install packages and dependencies for postorius and hyperkitty Add user for # executing apps, change ownership for uwsgi+django files and set execution # rights for management script RUN --mount=type=cache,target=/root/.cache \ set -ex \ - && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers \ + && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers libldap \ postgresql-dev mariadb-dev mariadb-connector-c python3-dev libffi-dev openldap-dev cargo rust \ - && apk add --no-cache --virtual .mailman-rundeps bash sassc \ + && apk add --no-cache --virtual .mailman-rundeps bash sassc tzdata \ postgresql-client mysql-client py3-mysqlclient curl mailcap gettext \ python3 py3-pip xapian-core xapian-bindings-python3 libffi pcre-dev py-cryptography \ - && python3 -m pip install -U 'Django<3.2' pip setuptools wheel \ - && pip install mailmanclient==3.3.3 \ - postorius==1.3.6 \ - hyperkitty==1.3.5 \ - django-mailman3==1.3.7 \ - mistune==2.0.0rc1 \ + && python3 -m pip install --break-system-packages -U 'Django<4.3' pip setuptools wheel \ + && pip install --break-system-packages -r /tmp/requirements.txt \ whoosh \ uwsgi \ - 'psycopg2<2.9' \ + psycopg2 \ dj-database-url \ mysqlclient \ typing \ xapian-haystack \ django-auth-ldap \ - python-memcached \ + pymemcache \ diskcache \ django-utils-six \ + tzdata \ + 'django-allauth[socialaccount,openid]' \ && apk del .build-deps \ && addgroup -S mailman \ - && adduser -S -G mailman mailman \ - && chown -R mailman /opt/mailman-web/ \ + && adduser -S -G mailman mailman + +# Add needed files for uwsgi server + settings for django +COPY mailman-web /opt/mailman-web +# Add startup script to container +COPY docker-entrypoint.sh /usr/local/bin/ + +RUN chown -R mailman /opt/mailman-web/ \ && chmod u+x /opt/mailman-web/manage.py WORKDIR /opt/mailman-web diff --git a/web/Dockerfile.dev b/web/Dockerfile.dev index 9b2809c..7c93f3c 100644 --- a/web/Dockerfile.dev +++ b/web/Dockerfile.dev @@ -1,10 +1,5 @@ # syntax = docker/dockerfile:1.3 -FROM alpine:3.12 - -# Add needed files for uwsgi server + settings for django -COPY mailman-web /opt/mailman-web -# Add startup script to container -COPY docker-entrypoint.sh /usr/local/bin/ +FROM alpine:3.20.0 ARG POSTORIUS_REF ARG HYPERKITTY_REF @@ -16,34 +11,42 @@ ARG CLIENT_REF # rights for management script RUN --mount=type=cache,target=/root/.cache \ set -ex \ - && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers git \ + && apk add --no-cache --virtual .build-deps gcc libc-dev linux-headers git libldap \ postgresql-dev mariadb-dev mariadb-connector-c python3-dev libffi-dev openldap-dev cargo rust \ - && apk add --no-cache --virtual .mailman-rundeps bash sassc pcre-dev \ + && apk add --no-cache --virtual .mailman-rundeps bash sassc pcre-dev tzdata \ python3 py3-pip postgresql-client mysql-client py3-mysqlclient \ curl mailcap xapian-core xapian-bindings-python3 libffi gettext py-cryptography \ - && python3 -m pip install -U pip setuptools wheel \ - && python3 -m pip install -U \ + && python3 -m pip install --break-system-packages -U pip setuptools wheel \ + && python3 -m pip install --break-system-packages -U \ git+https://gitlab.com/mailman/mailmanclient \ git+https://gitlab.com/mailman/postorius \ git+https://gitlab.com/mailman/hyperkitty \ whoosh \ uwsgi \ - 'psycopg2<2.9' \ + psycopg2 \ dj-database-url \ mysqlclient \ xapian-haystack \ django-auth-ldap \ - python-memcached \ + pymemcache \ + tzdata \ diskcache \ django-utils-six \ - && python3 -m pip install -U 'Django<3.2' \ - && python3 -m pip install -U \ + 'django-allauth[socialaccount,openid]' \ + && python3 -m pip install --break-system-packages -U 'Django<4.3' \ + && python3 -m pip install --break-system-packages -U \ git+https://gitlab.com/mailman/django-mailman3 \ && apk del .build-deps \ && addgroup -S mailman \ - && adduser -S -G mailman mailman \ - && chown -R mailman /opt/mailman-web/ \ - && chmod u+x /opt/mailman-web/manage.py + && adduser -S -G mailman mailman + +# Add needed files for uwsgi server + settings for django +COPY mailman-web /opt/mailman-web +# Add startup script to container +COPY docker-entrypoint.sh /usr/local/bin/ + +RUN chown -R mailman /opt/mailman-web/ \ + && chmod u+x /opt/mailman-web/manage.py WORKDIR /opt/mailman-web diff --git a/web/README.md b/web/README.md index 3bedcbb..c1116cf 100644 --- a/web/README.md +++ b/web/README.md @@ -56,16 +56,16 @@ change them unless you know what you want. - `SMTP_HOST_PASSWORD`: Default is an empty string. - `SMTP_USE_TLS`: Specifies wheather the SMTP connection is encrypted - via TLS. Default is `False`. + via TLS. Default is `False`. (`EMAIL_USE_TLS`/`EMAIL_USE_SSL` are mutually exclusive, so only set one of those settings.) - `SMTP_USE_SSL`: Specifies wheather the SMTP connection is encrypted - via SSL. Default is `False`. + via SSL. Default is `False`. (EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set one of those settings.) - `DJANGO_LOG_URL`: Path to the django's log file. Defaults to `/opt/mailman-web-data/logs/mailmanweb.log`. - `DJANGO_ALLOWED_HOSTS`: Entry to add to ALLOWED_HOSTS in Django - configuration. This is a separate configuration from`SERVE_FROM_DOMAIN` as + configuration. Format as comma-separated list (no whitespace). This is a separate configuration from`SERVE_FROM_DOMAIN` as latter is used for other purposes too. - `POSTORIUS_TEMPLATE_BASE_URL`: The base url at which the `mailman-web` diff --git a/web/docker-entrypoint.sh b/web/docker-entrypoint.sh index 4c86313..c00f015 100755 --- a/web/docker-entrypoint.sh +++ b/web/docker-entrypoint.sh @@ -7,7 +7,7 @@ function wait_for_postgres () { # moving forward. # TODO: Use python's psycopg2 module to do this in python instead of # installing postgres-client in the image. - until psql $DATABASE_URL -c '\l'; do + until psql -P pager=off $DATABASE_URL -c '\l'; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done @@ -118,12 +118,12 @@ echo "Compiling locale files in $SITE_DIR" cd $SITE_DIR && /opt/mailman-web/manage.py compilemessages && cd - # Compress static files. -python3 manage.py compress --force +python3 /opt/mailman-web/manage.py compress --force # Migrate all the data to the database if this is a new installation, otherwise # this command will upgrade the database. -python3 manage.py migrate +python3 /opt/mailman-web/manage.py migrate # If MAILMAN_ADMIN_USER and MAILMAN_ADMIN_EMAIL is defined create a new # superuser for Django. There is no password setup so it can't login yet unless @@ -131,7 +131,7 @@ python3 manage.py migrate if [[ -v MAILMAN_ADMIN_USER ]] && [[ -v MAILMAN_ADMIN_EMAIL ]]; then echo "Creating admin user $MAILMAN_ADMIN_USER ..." - python3 manage.py createsuperuser --noinput --username "$MAILMAN_ADMIN_USER"\ + python3 /opt/mailman-web/manage.py createsuperuser --noinput --username "$MAILMAN_ADMIN_USER"\ --email "$MAILMAN_ADMIN_EMAIL" 2> /dev/null || \ echo "Superuser $MAILMAN_ADMIN_USER already exists" fi @@ -141,7 +141,7 @@ fi if [[ -v SERVE_FROM_DOMAIN ]]; then echo "Setting $SERVE_FROM_DOMAIN as the default domain ..." - python3 manage.py shell -c \ + python3 /opt/mailman-web/manage.py shell -c \ "from django.contrib.sites.models import Site; Site.objects.filter(domain='example.com').update(domain='$SERVE_FROM_DOMAIN', name='$SERVE_FROM_DOMAIN')" fi diff --git a/web/mailman-web/settings.py b/web/mailman-web/settings.py index 6c2d0d0..c19a827 100644 --- a/web/mailman-web/settings.py +++ b/web/mailman-web/settings.py @@ -29,7 +29,7 @@ https://docs.djangoproject.com/en/1.8/ref/settings/ import os import dj_database_url import sys -from socket import gethostbyname +from socket import gethostbyname, gaierror BASE_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -49,14 +49,17 @@ SITE_ID = 1 # See https://docs.djangoproject.com/en/3.1/ref/settings/#allowed-hosts ALLOWED_HOSTS = [ "localhost", # Archiving API from Mailman, keep it. - # "lists.your-domain.org", - # Add here all production URLs you may have. "mailman-web", - gethostbyname("mailman-web"), os.environ.get('SERVE_FROM_DOMAIN'), - os.environ.get('DJANGO_ALLOWED_HOSTS'), ] +try: + ALLOWED_HOSTS.append(gethostbyname("mailman-web")) # only add if this resolves +except gaierror: + pass + +ALLOWED_HOSTS.extend(os.getenv("DJANGO_ALLOWED_HOSTS", "").split(",")) + # Mailman API credentials MAILMAN_REST_API_URL = os.environ.get('MAILMAN_REST_URL', 'http://mailman-core:8001') MAILMAN_REST_API_USER = os.environ.get('MAILMAN_REST_USER', 'restadmin') @@ -81,6 +84,7 @@ DEFAULT_APPS = [ 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django.contrib.humanize', 'rest_framework', 'django_gravatar', 'compressor', @@ -109,6 +113,7 @@ MIDDLEWARE = ( 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', + 'allauth.account.middleware.AccountMiddleware', 'django_mailman3.middleware.TimezoneMiddleware', 'postorius.middleware.PostoriusMiddleware', ) @@ -151,6 +156,11 @@ DATABASES = { 'default': dj_database_url.config(conn_max_age=600) } +# Avoid Django 3.2+ warning +# https://github.com/maxking/docker-mailman/issues/595 +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + + # If you're behind a proxy, use the X-Forwarded-Host header # See https://docs.djangoproject.com/en/1.8/ref/settings/#use-x-forwarded-host USE_X_FORWARDED_HOST = True @@ -178,7 +188,7 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'UTC' +TIME_ZONE = os.environ.get('TZ', 'UTC') USE_I18N = True diff --git a/web/mailman-web/urls.py b/web/mailman-web/urls.py index e8bb66c..19d49f9 100644 --- a/web/mailman-web/urls.py +++ b/web/mailman-web/urls.py @@ -16,20 +16,19 @@ # You should have received a copy of the GNU General Public License along with # Postorius. If not, see . - -from django.conf.urls import include, url +from django.conf.urls import include from django.contrib import admin -from django.urls import reverse_lazy +from django.urls import path, reverse_lazy from django.views.generic import RedirectView urlpatterns = [ - url(r'^$', RedirectView.as_view( + path(r'', RedirectView.as_view( url=reverse_lazy('list_index'), permanent=True)), - url(r'^postorius/', include('postorius.urls')), - url(r'^hyperkitty/', include('hyperkitty.urls')), - url(r'', include('django_mailman3.urls')), - url(r'^accounts/', include('allauth.urls')), + path(r'postorius/', include('postorius.urls')), + path(r'hyperkitty/', include('hyperkitty.urls')), + path(r'', include('django_mailman3.urls')), + path(r'accounts/', include('allauth.urls')), # Django admin - url(r'^admin/', admin.site.urls), + path(r'admin/', admin.site.urls), ] diff --git a/web/mailman-web/uwsgi.ini b/web/mailman-web/uwsgi.ini index 5856f4c..897ebad 100644 --- a/web/mailman-web/uwsgi.ini +++ b/web/mailman-web/uwsgi.ini @@ -3,10 +3,13 @@ uwsgi-socket = 0.0.0.0:8080 http-socket = 0.0.0.0:8000 -#Enable threading for python +# Enable threading for python enable-threads = true -# Move to the directory wher the django files are. +# Setting uwsgi buffer size to what Apache2 supports. +buffer-size = 8190 + +# Move to the directory where the django files are. chdir = /opt/mailman-web # Use the wsgi file provided with the django project. @@ -17,7 +20,7 @@ master = true processes = 2 threads = 2 -# Drop privielges and don't run as root. +# Drop privileges and don't run as root. uid = mailman gid = mailman diff --git a/web/requirements.txt b/web/requirements.txt new file mode 100644 index 0000000..e6dcc61 --- /dev/null +++ b/web/requirements.txt @@ -0,0 +1,4 @@ +mailmanclient==3.3.5 +postorius==1.3.10 +hyperkitty==1.3.9 +django-mailman3==1.3.11 \ No newline at end of file