summaryrefslogtreecommitdiffstats
path: root/scripts/docker
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/docker')
-rw-r--r--scripts/docker/README.md200
-rw-r--r--scripts/docker/dists/alpine/Dockerfile95
-rwxr-xr-xscripts/docker/dists/alpine/docker-entrypoint.sh27
-rw-r--r--scripts/docker/dists/centos7/Dockerfile134
-rwxr-xr-xscripts/docker/dists/centos7/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/debian10/Dockerfile82
-rwxr-xr-xscripts/docker/dists/debian10/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/debian11/Dockerfile87
-rwxr-xr-xscripts/docker/dists/debian11/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/debian12/Dockerfile87
-rwxr-xr-xscripts/docker/dists/debian12/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/debiansid/Dockerfile87
-rwxr-xr-xscripts/docker/dists/debiansid/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/rocky8/Dockerfile145
-rwxr-xr-xscripts/docker/dists/rocky8/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/rocky9/Dockerfile124
-rwxr-xr-xscripts/docker/dists/rocky9/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/ubuntu18/Dockerfile82
-rwxr-xr-xscripts/docker/dists/ubuntu18/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/ubuntu20/Dockerfile82
-rwxr-xr-xscripts/docker/dists/ubuntu20/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/ubuntu22/Dockerfile87
-rwxr-xr-xscripts/docker/dists/ubuntu22/docker-entrypoint.sh24
-rw-r--r--scripts/docker/dists/ubuntu24/Dockerfile87
-rw-r--r--scripts/docker/docker.mk211
-rwxr-xr-xscripts/docker/etc/docker-entrypoint.sh.alpine27
-rwxr-xr-xscripts/docker/etc/docker-entrypoint.sh.deb24
-rwxr-xr-xscripts/docker/etc/docker-entrypoint.sh.rpm24
-rw-r--r--scripts/docker/m4/Dockerfile.alpine.m490
-rw-r--r--scripts/docker/m4/Dockerfile.deb.m488
-rw-r--r--scripts/docker/m4/Dockerfile.m445
-rw-r--r--scripts/docker/m4/Dockerfile.rpm.m4186
32 files changed, 2341 insertions, 0 deletions
diff --git a/scripts/docker/README.md b/scripts/docker/README.md
new file mode 100644
index 0000000..f6e9ae6
--- /dev/null
+++ b/scripts/docker/README.md
@@ -0,0 +1,200 @@
+# What is FreeRADIUS?
+
+The FreeRADIUS Server Project is a high performance and highly
+configurable multi-protocol policy server, supporting RADIUS, DHCPv4
+and VMPS. Using RADIUS allows authentication and authorization for a network
+to be centralized, and minimizes the number of changes that have to
+be done when adding or deleting new users to a network.
+
+FreeRADIUS can authenticate users on systems such as 802.1x
+(WiFi), dialup, PPPoE, VPN's, VoIP, and many others. It supports
+back-end databases such as MySQL, PostgreSQL, Oracle, Microsoft
+Active Directory, Redis, OpenLDAP. It is used daily to
+authenticate the Internet access for hundreds of millions of
+people, in sites ranging from 10 to 10 million+ users.
+
+> [wikipedia.org/wiki/FreeRADIUS](https://en.wikipedia.org/wiki/FreeRADIUS)
+
+
+# How to use this image
+
+## Starting the server
+
+```console
+$ docker run --name my-radius -d freeradius/freeradius-server
+```
+
+The image contains only the default FreeRADIUS configuration which
+has no users, and accepts test clients on 127.0.0.1. In order to
+use it in production, as a minimum you will need to add clients to
+the `clients.conf` file, and users to the "users" file in
+`mods-config/files/authorize`.
+
+**Without building a local image with a configuration, the
+container will refuse to answer any queries.**
+
+
+## Defining a local configuration
+
+Create a local `Dockerfile` based on the required image and
+COPY in the server configuration.
+
+```Dockerfile
+FROM freeradius/freeradius-server:latest
+COPY raddb/ /etc/raddb/
+```
+
+The `raddb` directory could contain, for example:
+
+```
+clients.conf
+mods-config/
+mods-config/files/
+mods-config/files/authorize
+```
+
+Where `clients.conf` contains a simple client definition
+
+```
+client dockernet {
+ ipaddr = 172.17.0.0/16
+ secret = testing123
+}
+```
+
+and the `authorize` "users" file contains a test user:
+
+```
+bob Cleartext-Password := "test"
+```
+
+Build the image locally:
+
+```console
+$ docker build -t my-radius-image -f Dockerfile .
+```
+
+
+## Using the local configuration
+
+It should now be possible to test authentication against the
+server from the host machine, using the `radtest` utility supplied
+with FreeRADIUS and the credentials defined above.
+
+Start the local container. Ports will need to be forwarded to the
+server, typically 1812/udp and/or 1813/udp, for example:
+
+```console
+docker run --rm -d --name my-radius -p 1812-1813:1812-1813/udp my-radius-image
+```
+
+Send a test request, you will need the `radtest` utility:
+
+```console
+$ radtest bob test 127.0.0.1 0 testing123
+```
+
+which should return an "Access-Accept".
+
+The image can now be stopped with:
+
+```console
+docker stop my-radius
+```
+
+
+## Running in debug mode
+
+FreeRADIUS should always be tested in debug mode, using option
+`-X`. Coloured debug output also requres `-t` be passed to docker.
+
+```console
+$ docker run --rm --name my-radius -t -p 1812-1813:1812-1813/udp freeradius/freeradius-server -X
+```
+
+Guidelines for how to read and interpret the debug output are on the
+[FreeRADIUS Wiki](https://wiki.freeradius.org/radiusd-X).
+
+
+## Security notes
+
+The configuration in the docker image comes with self-signed
+certificates for convenience. These should not be used in a
+production environment, but replaced with new certificates. See
+the file `raddb/certs/README.md` for more information.
+
+
+## Debugging
+
+By default if you try to use `gdb` in a Docker container, the
+pattach call will fail, and you will not be able to trace
+processes.
+
+In order to allow tracing, the ``--privileged`` flag must be
+passed to ``docker run``, this restores any Linux ``cap``
+privileges that would not ordinarily be given.
+
+
+# Image variants
+
+## `freeradius/freeradius-server:<version>`
+
+The de-facto image which should be used unless you know you need
+another image. It is based on
+[Ubuntu Linux](https://hub.docker.com/_/ubuntu/) Docker images.
+
+
+## `freeradius/freeradius-server:<version>-alpine`
+
+Image based on the [Alpine Linux](https://hub.docker.com/_/alpine/)
+Docker images, which are much smaller than most Linux
+distributions. To keep the basic size as small as possible, **this
+image does not include libraries for all modules that have been
+built** (especially the languages such as Perl or Python). Therefore
+these extra libraries will need to be installed with `apk add` in
+your own Dockerfile if you intend on using modules that require
+them.
+
+
+# Building Docker images
+
+The FreeRADIUS source contains Dockerfiles for several Linux
+distributions. They are in
+[`freeradius-server/scripts/docker/<os_name>`](https://github.com/FreeRADIUS/freeradius-server/tree/v3.2.x/scripts/docker).
+
+Build an image with
+
+```bash
+$ cd scripts/docker/<os_name>
+$ docker build . -t freeradius-<os_name>
+```
+
+This will download the OS base image, install/build any dependencies
+as necessary, perform a shallow clone of the FreeRADIUS source and
+build the server.
+
+Once built, running ``docker images`` should show the image.
+
+```bash
+$ docker images
+REPOSITORY TAG IMAGE ID CREATED SIZE
+freeradius-ubuntu16 latest 289b3c7aca94 4 minutes ago 218MB
+freeradius-alpine latest d7fb3041bea2 2 hours ago 88.6MB
+```
+
+
+## Build args
+
+Two ARGs are defined in the Dockerfiles that specify the source
+repository and git tag that the release will be built from. These
+are
+
+- source: the git repository URL
+- release: the git commit/tag
+
+To build the image from a specific repository and git tag, set one
+or both of these args:
+
+```console
+$ docker build . --build-arg=release=v3.2.x --build-arg=source=https://github.com/FreeRADIUS/freeradius-server.git -t freeradius-<os_name>
+```
diff --git a/scripts/docker/dists/alpine/Dockerfile b/scripts/docker/dists/alpine/Dockerfile
new file mode 100644
index 0000000..04c0101
--- /dev/null
+++ b/scripts/docker/dists/alpine/Dockerfile
@@ -0,0 +1,95 @@
+# Auto generated for alpine
+# from scripts/docker/m4/Dockerfile.alpine.m4
+#
+# Rebuild this file with `make docker.alpine.regen`
+#
+ARG from=alpine:3.13
+FROM ${from} as build
+
+#
+# Install build tools
+#
+RUN apk update
+RUN apk add git gcc make
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+RUN [ -z "$release" ] || git checkout ${release}
+
+
+#
+# Install build dependencies
+#
+# essential
+RUN apk add libc-dev talloc-dev
+RUN apk add openssl openssl-dev
+RUN apk add linux-headers
+# general
+RUN apk add pcre-dev libidn-dev krb5-dev samba-dev curl-dev json-c-dev
+RUN apk add openldap-dev unbound-dev
+# languages
+RUN apk add ruby-dev perl-dev python2-dev python3-dev
+# databases
+RUN apk add hiredis-dev libmemcached-dev gdbm-dev libcouchbase-dev
+# sql
+RUN apk add postgresql-dev mariadb-dev unixodbc-dev sqlite-dev
+
+#
+# Build the server
+#
+RUN ./configure --prefix=/opt
+RUN make -j2
+RUN make install
+RUN rm /opt/lib/*.a
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /opt /opt
+
+#
+# These are needed for the server to start
+#
+RUN apk update \
+ && apk add talloc libressl pcre libwbclient tzdata \
+ \
+#
+# Libraries that are needed dependent on which modules are used
+# Some of these (especially the languages) are huge. A reasonable
+# selection has been enabled here. If you use modules needing
+# other dependencies then install any others required in your
+# local Dockerfile.
+#
+ && apk add libcurl json-c libldap hiredis sqlite-dev \
+#RUN apk add libidn krb5
+#RUN apk add unbound-libs
+#RUN apk add ruby-libs perl python2-dev python3-dev
+#RUN apk add libmemcached gdbm libcouchbase
+#RUN apk add postgresql-dev mariadb-dev unixodbc-dev
+ \
+ && ln -s /opt/etc/raddb /etc/raddb
+
+WORKDIR /
+COPY scripts/docker//etc/docker-entrypoint.sh.alpine docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/dists/alpine/docker-entrypoint.sh b/scripts/docker/dists/alpine/docker-entrypoint.sh
new file mode 100755
index 0000000..e0f9f6f
--- /dev/null
+++ b/scripts/docker/dists/alpine/docker-entrypoint.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+PATH=/opt/sbin:/opt/bin:$PATH
+export PATH
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/centos7/Dockerfile b/scripts/docker/dists/centos7/Dockerfile
new file mode 100644
index 0000000..0e266b7
--- /dev/null
+++ b/scripts/docker/dists/centos7/Dockerfile
@@ -0,0 +1,134 @@
+# Auto generated for centos7
+# from scripts/docker/m4/Dockerfile.rpm.m4
+#
+# Rebuild this file with `make docker.centos7.regen`
+#
+ARG from=centos:7
+FROM ${from} as build
+
+#
+# CentOS 7 is now EOL, so we need to fix up the repo source
+#
+RUN sed -i "s/^mirrorlist/#mirrorlist/g" /etc/yum.repos.d/CentOS-*
+RUN sed -i "s|#\s*baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
+
+
+
+#
+# Install build tools
+#
+RUN yum groupinstall -y "Development Tools"
+RUN yum install -y rpmdevtools
+RUN yum install -y openssl
+
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Other requirements
+#
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+# Enable EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
+
+#
+# Install build dependencies
+#
+# Run twice, it doesn't always get everything with one invocation
+#
+RUN [ -e redhat/freeradius.spec ] && \
+ yum-builddep -y redhat/freeradius.spec && \
+ yum-builddep -y redhat/freeradius.spec
+
+#
+# Create RPM build environment
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
+
+RUN ./configure
+RUN cp VERSION /VERSION
+RUN make freeradius-server-$(cat /VERSION).tar.bz2
+RUN cp freeradius-server-$(cat /VERSION).tar.bz2 $BUILDDIR/SOURCES/
+RUN cp -r redhat/* $BUILDDIR/SOURCES/
+RUN sed -i "s/^Version:.*/Version: $(cat /VERSION)/" redhat/freeradius.spec
+RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/
+WORKDIR $BUILDDIR
+
+#
+# Build the server
+#
+ENV QA_RPATHS=0x0003
+RUN rpmbuild -bb --define "_release $(cat /VERSION)" "$BUILDDIR/SPECS/freeradius.spec"
+
+RUN mkdir /root/rpms
+RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+
+COPY --from=build /root/rpms /tmp/
+
+#
+# CentOS 7 is now EOL, so we need to fix up the repo source
+#
+RUN sed -i "s/^mirrorlist/#mirrorlist/g" /etc/yum.repos.d/CentOS-*
+RUN sed -i "s|#\s*baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
+
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo \
+ && rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+
+# EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
+ \
+ && yum install -y /tmp/*.rpm
+
+WORKDIR /
+COPY scripts/docker//etc/docker-entrypoint.sh.rpm docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/dists/centos7/docker-entrypoint.sh b/scripts/docker/dists/centos7/docker-entrypoint.sh
new file mode 100755
index 0000000..900ad6b
--- /dev/null
+++ b/scripts/docker/dists/centos7/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/debian10/Dockerfile b/scripts/docker/dists/debian10/Dockerfile
new file mode 100644
index 0000000..5e9e9a5
--- /dev/null
+++ b/scripts/docker/dists/debian10/Dockerfile
@@ -0,0 +1,82 @@
+# Auto generated for debian10
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.debian10.regen`
+#
+ARG from=debian:buster
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+RUN apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/debian10/docker-entrypoint.sh b/scripts/docker/dists/debian10/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/debian10/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/debian11/Dockerfile b/scripts/docker/dists/debian11/Dockerfile
new file mode 100644
index 0000000..f709d95
--- /dev/null
+++ b/scripts/docker/dists/debian11/Dockerfile
@@ -0,0 +1,87 @@
+# Auto generated for debian11
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.debian11.regen`
+#
+ARG from=debian:bullseye
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/debian11/docker-entrypoint.sh b/scripts/docker/dists/debian11/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/debian11/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/debian12/Dockerfile b/scripts/docker/dists/debian12/Dockerfile
new file mode 100644
index 0000000..609e8ae
--- /dev/null
+++ b/scripts/docker/dists/debian12/Dockerfile
@@ -0,0 +1,87 @@
+# Auto generated for debian12
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.debian12.regen`
+#
+ARG from=debian:bookworm
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/debian12/docker-entrypoint.sh b/scripts/docker/dists/debian12/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/debian12/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/debiansid/Dockerfile b/scripts/docker/dists/debiansid/Dockerfile
new file mode 100644
index 0000000..862a421
--- /dev/null
+++ b/scripts/docker/dists/debiansid/Dockerfile
@@ -0,0 +1,87 @@
+# Auto generated for debiansid
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.debiansid.regen`
+#
+ARG from=debian:sid
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/debiansid/docker-entrypoint.sh b/scripts/docker/dists/debiansid/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/debiansid/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/rocky8/Dockerfile b/scripts/docker/dists/rocky8/Dockerfile
new file mode 100644
index 0000000..4dcb92e
--- /dev/null
+++ b/scripts/docker/dists/rocky8/Dockerfile
@@ -0,0 +1,145 @@
+# Auto generated for rocky8
+# from scripts/docker/m4/Dockerfile.rpm.m4
+#
+# Rebuild this file with `make docker.rocky8.regen`
+#
+ARG from=rockylinux/rockylinux:8
+FROM ${from} as build
+
+#
+# Install yum
+#
+RUN dnf install -y yum
+
+RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial
+
+#
+# Install build tools
+#
+RUN yum groupinstall -y "Development Tools"
+
+RUN yum install -y rpmdevtools openssl dnf-utils
+
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Other requirements
+#
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+# Enable EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
+
+# Enable powertools repo
+RUN yum config-manager --enable powertools
+
+# Enable epel-testing, currently needed for hiredis-devel
+RUN yum config-manager --enable epel-testing
+
+#
+# Install build dependencies
+#
+# Run twice, it doesn't always get everything with one invocation
+#
+RUN [ -e redhat/freeradius.spec ] && \
+ yum-builddep -y redhat/freeradius.spec && \
+ yum-builddep -y redhat/freeradius.spec
+
+#
+# Create RPM build environment
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
+
+RUN ./configure
+RUN cp VERSION /VERSION
+RUN make freeradius-server-$(cat /VERSION).tar.bz2
+RUN cp freeradius-server-$(cat /VERSION).tar.bz2 $BUILDDIR/SOURCES/
+RUN cp -r redhat/* $BUILDDIR/SOURCES/
+RUN sed -i "s/^Version:.*/Version: $(cat /VERSION)/" redhat/freeradius.spec
+RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/
+WORKDIR $BUILDDIR
+
+#
+# Build the server
+#
+ENV QA_RPATHS=0x0003
+RUN rpmbuild -bb --define "_release $(cat /VERSION)" "$BUILDDIR/SPECS/freeradius.spec"
+
+RUN mkdir /root/rpms
+RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+
+COPY --from=build /root/rpms /tmp/
+
+#
+# Install yum
+#
+RUN dnf install -y yum
+
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo \
+ && rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+
+
+# EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \
+ && yum install -y dnf-utils \
+ && yum config-manager --enable powertools \
+ && yum config-manager --enable epel-testing
+
+ARG radiusd_uid=95
+ARG radiusd_gid=95
+
+RUN groupadd -g ${radiusd_gid} -r radiusd \
+ && useradd -u ${radiusd_uid} -g radiusd -r -M -d /home/radiusd -s /sbin/nologin radiusd \
+ && yum install -y /tmp/*.rpm
+
+WORKDIR /
+COPY scripts/docker//etc/docker-entrypoint.sh.rpm docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/dists/rocky8/docker-entrypoint.sh b/scripts/docker/dists/rocky8/docker-entrypoint.sh
new file mode 100755
index 0000000..900ad6b
--- /dev/null
+++ b/scripts/docker/dists/rocky8/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/rocky9/Dockerfile b/scripts/docker/dists/rocky9/Dockerfile
new file mode 100644
index 0000000..0f57010
--- /dev/null
+++ b/scripts/docker/dists/rocky9/Dockerfile
@@ -0,0 +1,124 @@
+# Auto generated for rocky9
+# from scripts/docker/m4/Dockerfile.rpm.m4
+#
+# Rebuild this file with `make docker.rocky9.regen`
+#
+ARG from=rockylinux/rockylinux:9
+FROM ${from} as build
+
+#
+# Install yum
+#
+RUN dnf install -y yum
+
+RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
+
+#
+# Install build tools
+#
+RUN yum groupinstall -y "Development Tools"
+
+RUN yum install -y rpmdevtools openssl dnf-utils
+
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Other requirements
+#
+
+# Enable EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
+
+# Enable Code Ready Builder repo (CentOS powertools equivalent)
+RUN yum install -y yum-utils
+RUN yum config-manager --enable crb
+
+#
+# Install build dependencies
+#
+# Run twice, it doesn't always get everything with one invocation
+#
+RUN [ -e redhat/freeradius.spec ] && \
+ yum-builddep -y redhat/freeradius.spec && \
+ yum-builddep -y redhat/freeradius.spec
+
+#
+# Create RPM build environment
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
+
+RUN ./configure
+RUN cp VERSION /VERSION
+RUN make freeradius-server-$(cat /VERSION).tar.bz2
+RUN cp freeradius-server-$(cat /VERSION).tar.bz2 $BUILDDIR/SOURCES/
+RUN cp -r redhat/* $BUILDDIR/SOURCES/
+RUN sed -i "s/^Version:.*/Version: $(cat /VERSION)/" redhat/freeradius.spec
+RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/
+WORKDIR $BUILDDIR
+
+#
+# Build the server
+#
+ENV QA_RPATHS=0x0003
+RUN rpmbuild -bb --define "_release $(cat /VERSION)" "$BUILDDIR/SPECS/freeradius.spec"
+
+RUN mkdir /root/rpms
+RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+
+COPY --from=build /root/rpms /tmp/
+
+#
+# Install yum
+#
+RUN dnf install -y yum
+
+
+
+# EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm \
+ && yum install -y dnf-utils \
+ && yum config-manager --enable crb \
+ && yum config-manager --enable epel-testing
+
+ARG radiusd_uid=95
+ARG radiusd_gid=95
+
+RUN groupadd -g ${radiusd_gid} -r radiusd \
+ && useradd -u ${radiusd_uid} -g radiusd -r -M -d /home/radiusd -s /sbin/nologin radiusd \
+ && yum install -y /tmp/*.rpm
+
+WORKDIR /
+COPY scripts/docker//etc/docker-entrypoint.sh.rpm docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/dists/rocky9/docker-entrypoint.sh b/scripts/docker/dists/rocky9/docker-entrypoint.sh
new file mode 100755
index 0000000..900ad6b
--- /dev/null
+++ b/scripts/docker/dists/rocky9/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/ubuntu18/Dockerfile b/scripts/docker/dists/ubuntu18/Dockerfile
new file mode 100644
index 0000000..4e32632
--- /dev/null
+++ b/scripts/docker/dists/ubuntu18/Dockerfile
@@ -0,0 +1,82 @@
+# Auto generated for ubuntu18
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.ubuntu18.regen`
+#
+ARG from=ubuntu:18.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+RUN apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/ubuntu18/docker-entrypoint.sh b/scripts/docker/dists/ubuntu18/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/ubuntu18/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/ubuntu20/Dockerfile b/scripts/docker/dists/ubuntu20/Dockerfile
new file mode 100644
index 0000000..4a3bbf4
--- /dev/null
+++ b/scripts/docker/dists/ubuntu20/Dockerfile
@@ -0,0 +1,82 @@
+# Auto generated for ubuntu20
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.ubuntu20.regen`
+#
+ARG from=ubuntu:20.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+RUN apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/ubuntu20/docker-entrypoint.sh b/scripts/docker/dists/ubuntu20/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/ubuntu20/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/ubuntu22/Dockerfile b/scripts/docker/dists/ubuntu22/Dockerfile
new file mode 100644
index 0000000..778112a
--- /dev/null
+++ b/scripts/docker/dists/ubuntu22/Dockerfile
@@ -0,0 +1,87 @@
+# Auto generated for ubuntu22
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.ubuntu22.regen`
+#
+ARG from=ubuntu:22.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/dists/ubuntu22/docker-entrypoint.sh b/scripts/docker/dists/ubuntu22/docker-entrypoint.sh
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/dists/ubuntu22/docker-entrypoint.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/dists/ubuntu24/Dockerfile b/scripts/docker/dists/ubuntu24/Dockerfile
new file mode 100644
index 0000000..ad4520e
--- /dev/null
+++ b/scripts/docker/dists/ubuntu24/Dockerfile
@@ -0,0 +1,87 @@
+# Auto generated for ubuntu24
+# from scripts/docker/m4/Dockerfile.deb.m4
+#
+# Rebuild this file with `make docker.ubuntu24.regen`
+#
+ARG from=ubuntu:24.04
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.deb docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/docker.mk b/scripts/docker/docker.mk
new file mode 100644
index 0000000..bf556c6
--- /dev/null
+++ b/scripts/docker/docker.mk
@@ -0,0 +1,211 @@
+#
+# Docker-related targets
+#
+# Intended for internal use to publish Docker images to docker hub. Likely need to run
+# "docker login" before any push commands.
+#
+# Examples:
+#
+# Publish to Dockerhub "freeradius-server"
+# make DOCKER_VERSION=3.2.0 DOCKER_BUILD_ARGS="--no-cache" docker-publish
+#
+# Build and push "freeradius-dev" image to Dockerhub (e.g. CI on every commit):
+# make DOCKER_VERSION=latest DOCKER_COMMIT=v3.2.x DOCKER_TAG="freeradius-dev-3.2.x" DOCKER_BUILD_ARGS="--no-cache" docker-push
+#
+# Push to local repository:
+# make DOCKER_VERSION=3.2.0 DOCKER_TAG="our-freeradius-build" DOCKER_REGISTRY="docker.somewhere.example" docker-publish
+#
+# See what is going to happen:
+# make Q=": " ...
+#
+#
+# Variables:
+#
+# Which version to tag as, e.g. "3.2.0". If this is not an actual release
+# version, DOCKER_COMMIT _must_ also be set.
+DOCKER_VERSION := $(RADIUSD_VERSION_STRING)
+#
+# Commit hash/tag/branch to build, if not set then HEAD will be used.
+DOCKER_COMMIT :=
+#
+# Build args, most likely "--no-cache"
+DOCKER_BUILD_ARGS :=
+#
+# Tag name, likely "freeradius-server" for releases, or "freeradius-dev" for nightlies.
+DOCKER_TAG := freeradius-server
+#
+# Repository name
+DOCKER_REPO := freeradius
+#
+# Registry to push to
+DOCKER_REGISTRY :=
+#
+# Location of Docker-related files
+DOCKER_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+DIST_DIR := $(DOCKER_DIR)/dists
+#
+# List of images we can build
+DOCKER_IMAGES:=$(sort $(patsubst $(DIST_DIR)/%,%,$(wildcard $(DIST_DIR)/*)))
+
+DOCKER_DEFAULT_UBUNTU := ubuntu22
+DOCKER_DEFAULT_ALPINE := alpine
+
+ifeq "${VERBOSE}" ""
+ Q=@
+else
+ Q=
+endif
+
+
+ifneq "$(DOCKER_REPO)" ""
+ override DOCKER_REPO := $(DOCKER_REPO)/
+endif
+
+ifneq "$(DOCKER_REGISTRY)" ""
+ override DOCKER_REGISTRY := $(DOCKER_REGISTRY)/
+endif
+
+
+#
+# Print some useful help
+#
+.PHONY: docker.help.images
+docker.help.images:
+ @echo Available images: $(DOCKER_IMAGES)
+
+.PHONY: docker.help
+docker.help: docker.help.images
+ @echo ""
+ @echo "Make targets:"
+ @echo " docker-ubuntu - build main ubuntu image"
+ @echo " docker-alpine - build main alpine image"
+ @echo " docker.regen - regenerate all Dockerfiles from templates"
+ @echo ""
+ @echo "Make targets per image:"
+ @echo " docker.IMAGE.build - build image"
+ @echo " docker.IMAGE.regen - regenerate Dockerfile"
+ @echo ""
+ @echo "Arguments:"
+ @echo ' DOCKER_BUILD_ARGS="--no-cache" - extra build args'
+ @echo ' DOCKER_REGISTRY="docker.example.com" - registry to build for'
+ @echo ' DOCKER_REPO="freeradius" - docker repo name'
+ @echo ' DOCKER_TAG="freeradius-server" - docker tag name'
+ @echo ' DOCKER_COMMIT="HEAD" - commit/ref to build from'
+ @echo ' DOCKER_VERSION="$(DOCKER_VERSION)" - version for docker image name'
+
+
+#
+# Rules for each OS
+#
+
+define ADD_DOCKER_RULES
+ $$(DIST_DIR)/${1}/Dockerfile: $(DOCKER_DIR)/m4/Dockerfile.m4 $(DOCKER_DIR)/m4/Dockerfile.deb.m4 $(DOCKER_DIR)/m4/Dockerfile.rpm.m4 $(DOCKER_DIR)/m4/Dockerfile.alpine.m4 $(DOCKER_DIR)/docker.mk
+ $$(Q)echo REGEN ${1}/Dockerfile
+ $$(Q)m4 -I $(DOCKER_DIR)/m4 -D D_NAME=${1} -D D_TYPE=docker $$< > $$@
+
+ DOCKER_DOCKERFILES += $$(DIST_DIR)/${1}/Dockerfile
+
+ .PHONY: docker.${1}.regen
+ docker.${1}.regen: $$(DIST_DIR)/${1}/Dockerfile
+
+ .PHONY: docker.${1}.build
+ docker.${1}.build:
+ @echo BUILD ${1} $(DOCKER_COMMIT)
+ $(Q)docker buildx build \
+ $(DOCKER_BUILD_ARGS) \
+ --progress=plain \
+ --build-arg=release=$(DOCKER_COMMIT) \
+ -t $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-${1} \
+ -f $(DIST_DIR)/${1}/Dockerfile \
+ .
+
+endef
+
+$(foreach IMAGE,$(DOCKER_IMAGES), \
+ $(eval $(call ADD_DOCKER_RULES,$(IMAGE))))
+
+.PHONY: docker.regen
+docker.regen: $(DOCKER_DOCKERFILES)
+
+
+#
+# Rules to rebuild Docker images
+#
+.PHONY: docker-ubuntu
+docker-ubuntu: docker.$(DOCKER_DEFAULT_UBUNTU).build
+ $(Q)docker image tag \
+ $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-$(DOCKER_DEFAULT_UBUNTU) \
+ $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)
+
+.PHONY: docker-alpine
+docker-alpine: docker.$(DOCKER_DEFAULT_ALPINE).build
+ $(Q)docker image tag \
+ $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-$(DOCKER_DEFAULT_ALPINE) \
+ $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine
+
+.PHONY: docker
+docker: docker-ubuntu docker-alpine
+
+#
+# Push main ubuntu and alpine images (all below are separate for CI jobs)
+#
+.PHONY: docker-push-ubuntu
+docker-push-ubuntu:
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)
+
+.PHONY: docker-push-alpine
+docker-push-alpine:
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine
+
+.PHONY: docker-push
+docker-push: docker-push-ubuntu docker-push-alpine
+
+#
+# Tag main "latest" images
+#
+.PHONY: docker-tag-latest-ubuntu
+docker-tag-latest-ubuntu:
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION) $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION) $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2
+
+.PHONY: docker-tag-latest-alpine
+docker-tag-latest-alpine:
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-alpine
+ $(Q)docker tag $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)-alpine $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2-alpine
+
+.PHONY: docker-tag-latest
+docker-tag-latest: docker-tag-latest-ubuntu docker-tag-latest-alpine
+
+#
+# Push main "latest" images
+#
+.PHONY: docker-push-latest-ubuntu
+docker-push-latest-ubuntu: docker-push-ubuntu docker-tag-latest-ubuntu
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2
+
+.PHONY: docker-push-latest-alpine
+docker-push-latest-alpine: docker-push-alpine docker-tag-latest-alpine
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-alpine
+ $(Q)docker push $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):latest-3.2-alpine
+
+.PHONY: docker-push-latest
+docker-push-latest: docker-push-latest-ubuntu docker-push-latest-alpine
+
+#
+# Convenience target to do everything
+#
+.PHONY: docker-publish
+docker-publish: docker docker-push-latest
+
+#
+# Used for multi-arch CI job. "docker manifest" rather than "docker buildx
+# --platforms=...,..." so that we can parallelise the build in GH Actions.
+#
+.PHONY: docker-ci-manifest
+docker-ci-manifest:
+ $(Q)docker manifest create \
+ $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION) \
+ $(foreach ARCH,$(DOCKER_ARCHS),--amend $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(ARCH)-$(DOCKER_VERSION))
+ $(Q)docker manifest push \
+ $(DOCKER_REGISTRY)$(DOCKER_REPO)$(DOCKER_TAG):$(DOCKER_VERSION)
diff --git a/scripts/docker/etc/docker-entrypoint.sh.alpine b/scripts/docker/etc/docker-entrypoint.sh.alpine
new file mode 100755
index 0000000..e0f9f6f
--- /dev/null
+++ b/scripts/docker/etc/docker-entrypoint.sh.alpine
@@ -0,0 +1,27 @@
+#!/bin/sh
+set -e
+
+PATH=/opt/sbin:/opt/bin:$PATH
+export PATH
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/etc/docker-entrypoint.sh.deb b/scripts/docker/etc/docker-entrypoint.sh.deb
new file mode 100755
index 0000000..93141b0
--- /dev/null
+++ b/scripts/docker/etc/docker-entrypoint.sh.deb
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- freeradius "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# many people are likely to call "radiusd" as well, so allow that
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec freeradius -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/etc/docker-entrypoint.sh.rpm b/scripts/docker/etc/docker-entrypoint.sh.rpm
new file mode 100755
index 0000000..900ad6b
--- /dev/null
+++ b/scripts/docker/etc/docker-entrypoint.sh.rpm
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+# this if will check if the first argument is a flag
+# but only works if all arguments require a hyphenated flag
+# -v; -SL; -f arg; etc will work, but not arg1 arg2
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+ set -- radiusd "$@"
+fi
+
+# check for the expected command
+if [ "$1" = 'radiusd' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# debian people are likely to call "freeradius" as well, so allow that
+if [ "$1" = 'freeradius' ]; then
+ shift
+ exec radiusd -f "$@"
+fi
+
+# else default to run whatever the user wanted like "bash" or "sh"
+exec "$@"
diff --git a/scripts/docker/m4/Dockerfile.alpine.m4 b/scripts/docker/m4/Dockerfile.alpine.m4
new file mode 100644
index 0000000..64c6c8f
--- /dev/null
+++ b/scripts/docker/m4/Dockerfile.alpine.m4
@@ -0,0 +1,90 @@
+ARG from=DOCKER_IMAGE
+FROM ${from} as build
+
+#
+# Install build tools
+#
+RUN apk update
+RUN apk add git gcc make
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+RUN [ -z "$release" ] || git checkout ${release}
+
+
+#
+# Install build dependencies
+#
+# essential
+RUN apk add libc-dev talloc-dev
+RUN apk add openssl openssl-dev
+RUN apk add linux-headers
+# general
+RUN apk add pcre-dev libidn-dev krb5-dev samba-dev curl-dev json-c-dev
+RUN apk add openldap-dev unbound-dev
+# languages
+RUN apk add ruby-dev perl-dev python2-dev python3-dev
+# databases
+RUN apk add hiredis-dev libmemcached-dev gdbm-dev libcouchbase-dev
+# sql
+RUN apk add postgresql-dev mariadb-dev unixodbc-dev sqlite-dev
+
+#
+# Build the server
+#
+RUN ./configure --prefix=/opt
+RUN make -j2
+RUN make install
+RUN rm /opt/lib/*.a
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+COPY --from=build /opt /opt
+
+#
+# These are needed for the server to start
+#
+RUN apk update \
+ && apk add talloc libressl pcre libwbclient tzdata \
+ \
+#
+# Libraries that are needed dependent on which modules are used
+# Some of these (especially the languages) are huge. A reasonable
+# selection has been enabled here. If you use modules needing
+# other dependencies then install any others required in your
+# local Dockerfile.
+#
+ && apk add libcurl json-c libldap hiredis sqlite-dev \
+#RUN apk add libidn krb5
+#RUN apk add unbound-libs
+#RUN apk add ruby-libs perl python2-dev python3-dev
+#RUN apk add libmemcached gdbm libcouchbase
+#RUN apk add postgresql-dev mariadb-dev unixodbc-dev
+ \
+ && ln -s /opt/etc/raddb /etc/raddb
+
+WORKDIR /
+COPY DOCKER_TOPDIR/etc/docker-entrypoint.sh.PKG_TYPE docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]
diff --git a/scripts/docker/m4/Dockerfile.deb.m4 b/scripts/docker/m4/Dockerfile.deb.m4
new file mode 100644
index 0000000..0b4e5b5
--- /dev/null
+++ b/scripts/docker/m4/Dockerfile.deb.m4
@@ -0,0 +1,88 @@
+ARG from=DOCKER_IMAGE
+FROM ${from} as build
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+#
+# Install build tools
+#
+RUN apt-get update
+RUN apt-get install -y devscripts equivs git quilt gcc
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Install build dependencies
+#
+RUN if [ -e ./debian/control.in ]; then \
+ debian/rules debian/control; \
+ fi; \
+ echo 'y' | mk-build-deps -irt'apt-get -yV' debian/control
+
+#
+# Build the server
+#
+# Work around fakeroot problems in Docker when building for different
+# platforms - doesn't matter as we run as root in the container anyway.
+#
+#RUN make -j$(nproc) deb
+RUN debian/rules debian/control \
+ && dpkg-buildpackage --jobs=auto -b -uc
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+ARG DEBIAN_FRONTEND=noninteractive
+
+COPY --from=build /usr/local/src/repositories/*.deb /tmp/
+
+RUN ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+
+ifelse(ifelse(
+ D_NAME, `debian10', no,
+ D_NAME, `ubuntu18', no,
+ D_NAME, `ubuntu20', no,
+ yes), yes, `dnl
+ARG freerad_uid=101
+ARG freerad_gid=101
+
+RUN groupadd -g ${freerad_gid} -r freerad \
+ && useradd -u ${freerad_uid} -g freerad -r -M -d /etc/freeradius -s /usr/sbin/nologin freerad \
+ && apt-get update \',
+`RUN apt-get update \')
+ && apt-get install -y tzdata \
+ && apt-get install -y /tmp/*.deb \
+ && apt-get clean \
+ && rm -r /var/lib/apt/lists/* /tmp/*.deb \
+ \
+ && ln -s /etc/freeradius /etc/raddb
+
+WORKDIR /
+COPY scripts/docker/etc/docker-entrypoint.sh.PKG_TYPE docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["freeradius"]
diff --git a/scripts/docker/m4/Dockerfile.m4 b/scripts/docker/m4/Dockerfile.m4
new file mode 100644
index 0000000..f9890a1
--- /dev/null
+++ b/scripts/docker/m4/Dockerfile.m4
@@ -0,0 +1,45 @@
+dnl Look up the OS codename, docker base image etc before including
+dnl the main Dockerfile template.
+dnl
+dnl This top-level template is used by both the docker makefile
+dnl (scripts/docker/docker.mk) and the crossbuild makefile
+dnl (scripts/crossbuild/crossbuild.mk), but the Dockerfile templates
+dnl they use are different - see the m4 directories for each.
+dnl
+divert(`-1')
+changequote(`[', `]')
+define([DOCKER_TOPDIR], [scripts/docker/])
+define([p_SET], [
+ define([PKG_TYPE], [$1])
+ define([OS_NAME], [$2])
+ define([OS_VER], [$3])
+ define([OS_CODENAME], [$4])
+ define([DOCKER_IMAGE], [$5])
+])
+dnl D_NAME PKG_TYPE OS_NAME OS_VER OS_CODENAME DOCKER_IMAGE
+ifelse(
+ D_NAME, [alpine], [p_SET([alpine], [alpine], [3.13], [alpine], [alpine:3.13])],
+ D_NAME, [debian10], [p_SET([deb], [debian], [10], [buster], [debian:buster])],
+ D_NAME, [debian11], [p_SET([deb], [debian], [11], [bullseye], [debian:bullseye])],
+ D_NAME, [debian12], [p_SET([deb], [debian], [12], [bookworm], [debian:bookworm])],
+ D_NAME, [debiansid], [p_SET([deb], [debian], [99], [sid], [debian:sid])],
+ D_NAME, [ubuntu18], [p_SET([deb], [ubuntu], [18], [bionic], [ubuntu:18.04])],
+ D_NAME, [ubuntu20], [p_SET([deb], [ubuntu], [20], [focal], [ubuntu:20.04])],
+ D_NAME, [ubuntu22], [p_SET([deb], [ubuntu], [22], [jammy], [ubuntu:22.04])],
+ D_NAME, [ubuntu24], [p_SET([deb], [ubuntu], [24], [noble], [ubuntu:24.04])],
+ D_NAME, [centos7], [p_SET([rpm], [centos], [7], [7], [centos:7])],
+ D_NAME, [centos8], [p_SET([rpm], [centos], [8], [8], [centos:8])],
+ D_NAME, [rocky8], [p_SET([rpm], [rocky], [8], [8], [rockylinux/rockylinux:8])],
+ D_NAME, [rocky9], [p_SET([rpm], [rocky], [9], [9], [rockylinux/rockylinux:9])],
+ [errprint(error: OS 'D_NAME' not defined[,] see __file__
+)m4exit(1)]
+)
+undefine([p_SET])
+divert[]dnl
+[#] Auto generated for D_NAME
+[#] from scripts/D_TYPE/m4/Dockerfile.PKG_TYPE.m4
+[#]
+[#] Rebuild this file with `make D_TYPE.D_NAME.regen`
+[#]
+changequote([`], ['])dnl
+include(Dockerfile.PKG_TYPE.m4)dnl
diff --git a/scripts/docker/m4/Dockerfile.rpm.m4 b/scripts/docker/m4/Dockerfile.rpm.m4
new file mode 100644
index 0000000..03181e8
--- /dev/null
+++ b/scripts/docker/m4/Dockerfile.rpm.m4
@@ -0,0 +1,186 @@
+ARG from=DOCKER_IMAGE
+FROM ${from} as build
+
+ifelse(OS_VER, 7, `dnl
+#
+# CentOS 7 is now EOL, so we need to fix up the repo source
+#
+RUN sed -i "s/^mirrorlist/#mirrorlist/g" /etc/yum.repos.d/CentOS-*
+RUN sed -i "s|#\s*baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
+')dnl
+
+ifelse(OS_VER, `7', `', `dnl
+#
+# Install yum
+#
+RUN dnf install -y yum
+')dnl
+
+ifelse(OS_VER, 8, `dnl
+RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial
+')dnl
+ifelse(OS_VER, 9, `dnl
+RUN rpmkeys --import /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
+')
+#
+# Install build tools
+#
+RUN yum groupinstall -y "Development Tools"
+ifelse(OS_VER, 7,`dnl
+RUN yum install -y rpmdevtools
+RUN yum install -y openssl
+',`
+RUN yum install -y rpmdevtools openssl dnf-utils
+')
+
+#
+# Create build directory
+#
+RUN mkdir -p /usr/local/src/repositories/freeradius-server
+WORKDIR /usr/local/src/repositories/freeradius-server/
+
+#
+# Copy the FreeRADIUS directory in
+#
+COPY . .
+
+#
+# Clean up tree - we want to build from the latest commit, not from
+# any cruft left around on the local system
+#
+RUN git clean -fdxx \
+ && git reset --hard HEAD
+
+ARG release
+RUN [ -z "$release" ] || git checkout ${release} ; \
+ git status ; \
+ git log -1 --oneline
+
+#
+# Other requirements
+#
+changequote(`{', `}')dnl
+ifelse(ifelse(OS_VER, 7, yes, OS_VER, 8, yes, no), yes, {
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo
+RUN rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+})dnl
+changequote({`}, {'})dnl
+
+# Enable EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-OS_VER.noarch.rpm
+ifelse(OS_VER, 8, `
+# Enable powertools repo
+RUN yum config-manager --enable powertools
+
+# Enable epel-testing, currently needed for hiredis-devel
+RUN yum config-manager --enable epel-testing
+')dnl
+ifelse(OS_VER, 9, `
+# Enable Code Ready Builder repo (CentOS powertools equivalent)
+RUN yum install -y yum-utils
+RUN yum config-manager --enable crb
+')dnl
+
+#
+# Install build dependencies
+#
+# Run twice, it doesn't always get everything with one invocation
+#
+RUN [ -e redhat/freeradius.spec ] && \
+ yum-builddep -y redhat/freeradius.spec && \
+ yum-builddep -y redhat/freeradius.spec
+
+#
+# Create RPM build environment
+#
+ENV BUILDDIR=/root/rpmbuild
+RUN rpmdev-setuptree
+
+RUN ./configure
+RUN cp VERSION /VERSION
+RUN make freeradius-server-$(cat /VERSION).tar.bz2
+RUN cp freeradius-server-$(cat /VERSION).tar.bz2 $BUILDDIR/SOURCES/
+RUN cp -r redhat/* $BUILDDIR/SOURCES/
+RUN sed -i "s/^Version:.*/Version: $(cat /VERSION)/" redhat/freeradius.spec
+RUN cp -r redhat/freeradius.spec $BUILDDIR/SPECS/
+WORKDIR $BUILDDIR
+
+#
+# Build the server
+#
+ENV QA_RPATHS=0x0003
+RUN rpmbuild -bb --define "_release $(cat /VERSION)" "$BUILDDIR/SPECS/freeradius.spec"
+
+RUN mkdir /root/rpms
+RUN mv $BUILDDIR/RPMS/*/*.rpm /root/rpms/
+
+#
+# Clean environment and run the server
+#
+FROM ${from}
+
+COPY --from=build /root/rpms /tmp/
+
+ifelse(OS_VER, 7, `dnl
+#
+# CentOS 7 is now EOL, so we need to fix up the repo source
+#
+RUN sed -i "s/^mirrorlist/#mirrorlist/g" /etc/yum.repos.d/CentOS-*
+RUN sed -i "s|#\s*baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g" /etc/yum.repos.d/CentOS-*
+')dnl
+
+ifelse(OS_VER, `7', `', `dnl
+#
+# Install yum
+#
+RUN dnf install -y yum
+')dnl
+
+changequote(`{', `}')dnl
+ifelse(ifelse(OS_VER, 7, yes, OS_VER, 8, yes, no), yes, {dnl
+# Use LTB's openldap packages intead of the distribution version to avoid linking against NSS
+RUN echo $'[ltb-project]\n\
+name=LTB project packages\n\
+baseurl=https://ltb-project.org/rpm/$releasever/$basearch\n\
+enabled=1\n\
+gpgcheck=1\n\
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-LTB-project'\
+> /etc/yum.repos.d/ltb-project.repo \
+ && rpm --import https://ltb-project.org/lib/RPM-GPG-KEY-LTB-project
+})dnl
+changequote({`}, {'})dnl
+
+
+# EPEL repository for freetds and hiredis
+RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-OS_VER.noarch.rpm \
+ifelse(OS_VER, 7, ` \', `dnl
+ && yum install -y dnf-utils \
+ifelse(OS_VER, 8, `dnl
+ && yum config-manager --enable powertools \
+')dnl
+ifelse(OS_VER, 9, `dnl
+ && yum config-manager --enable crb \
+')dnl
+ && yum config-manager --enable epel-testing
+
+ARG radiusd_uid=95
+ARG radiusd_gid=95
+
+RUN groupadd -g ${radiusd_gid} -r radiusd \
+ && useradd -u ${radiusd_uid} -g radiusd -r -M -d /home/radiusd -s /sbin/nologin radiusd \')
+ && yum install -y /tmp/*.rpm
+
+WORKDIR /
+COPY DOCKER_TOPDIR/etc/docker-entrypoint.sh.PKG_TYPE docker-entrypoint.sh
+RUN chmod +x docker-entrypoint.sh
+
+EXPOSE 1812/udp 1813/udp
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["radiusd"]