What is it
ISPConfig is a hosting control panel for managing websites, email, DNS and FTP
accounts on Linux servers. Installing it normally means running the
"perfect server" guide against a bare OS. This project collapses all of
that into a single Docker image that runs systemd as
PID 1 and executes the official ISPConfig autoinstaller unattended on first boot.
Everything inside one container
- Web: nginx + nginx-extras, PHP-FPM 8.3 & 8.4 (Sury)
- Database: MariaDB
- Mail: Postfix, Dovecot, Rspamd, ClamAV, Postgrey
- DNS: BIND9
- FTP: Pure-FTPd (MySQL backend)
- Webmail & DB admin: Roundcube, phpMyAdmin
- CalDAV/CardDAV: Radicale
- Security: Jailkit, Fail2ban, Memcached
Quick start
git clone https://github.com/taavityrnpuu/ispconfig-docker.git
cd ispconfig-docker
docker compose build --build-arg BASE_IMAGE=ubuntu:24.04
docker compose up -d
First boot runs the ISPConfig autoinstaller and takes a few minutes. Watch it with:
docker compose logs -f ispconfig
When it's done, open https://<host>:8080 and log in.
| Account | User | Password |
|---|---|---|
| ISPConfig panel | admin | admin |
| MySQL root | root | rootpw |
| ISPConfig DB | ispconfig | isppw |
| Radicale | admin | admin |
Tutorial
1. Prerequisites
- Docker Engine and the Compose plugin (v2).
- A Linux host with the ports below free (especially 80/443/53).
- ~4 GB RAM and ~10 GB disk for the container + volumes.
2. Get the source
git clone https://github.com/taavityrnpuu/ispconfig-docker.git
cd ispconfig-docker
3. Configure (optional)
Set credentials and the distro in docker-compose.yml. The key
environment variables:
environment:
- MYSQL_ROOT_PASSWORD=rootpw # change me
- ISP_DB_PASSWORD=isppw # change me
- ISP_CONFIG_VERSION=3.2.12p1
Also set a real hostname in hostname: (it's used by mail/DNS).
4. Build
docker compose build --build-arg BASE_IMAGE=ubuntu:24.04
BASE_IMAGE accepts debian:12, ubuntu:22.04
or ubuntu:24.04.
5. Run
docker compose up -d
On first boot the container starts MariaDB, then runs the ISPConfig installer
against /etc/ispconfig/autoinstall.ini. This takes several minutes.
The install is one-shot — it marks itself done and won't run again on restart.
6. First login
Browse to https://<host>:8080 (the panel runs on its own port,
not 443). Accept the self-signed cert, log in as admin / admin, and
change the password immediately under System → Users.
7. Create your first site
In the panel: Sites → Website → Add new website. Choose a domain, pick PHP 8.3 (or 8.4), and the panel writes the nginx vhost + FPM pool for you. Create mail/DNS/FTP accounts the same way from their respective menus.
Configuration reference
Build arguments
| Argument | Default | Purpose |
|---|---|---|
BASE_IMAGE | debian:12 | Base OS (debian:12 / ubuntu:22.04 / ubuntu:24.04) |
PHP_VERSION | 8.4 | Extra Sury PHP version, decoupled from the base |
ISP_PHP_VERSION | 8.3 | The distro-default PHP ISPConfig's OS profile manages |
MYSQL_ROOT_PASSWORD | rootpw | MariaDB root password |
ISP_DB_PASSWORD | isppw | ISPConfig database password |
ISP_CONFIG_VERSION | 3.2.12p1 | ISPConfig release to install |
Exposed ports
| Service | Port(s) |
|---|---|
| ISPConfig panel | 8080 |
| SSH | 2222 |
| HTTP / HTTPS | 80 / 443 |
| SMTP / submission / SMTPS | 25 / 587 / 465 |
| IMAP / IMAPS | 143 / 993 |
| POP3 / POP3S | 110 / 995 |
| FTP (+ passive) | 21 / 20000-21000 |
| DNS (BIND) | 53 tcp + udp |
| Radicale | 5232 |
Persistent volumes
| Volume | Mount |
|---|---|
www | /var/www (sites) |
vmail | /var/vmail (mailboxes) |
db | /var/lib/mysql (MariaDB) |
journal | /var/log/journal |
FAQ
Why one container instead of one per service?
ISPConfig assumes a single host running all services together — its installer and panel manage system services directly. Splitting them into microservices would fight the panel rather than help it. Running the whole "server" as one privileged systemd container mirrors a dedicated VPS and keeps the panel's expectations intact.
Is it production-ready?
It runs a genuine ISPConfig install with all its services, but the default
credentials are placeholders and it's privileged: true. Change the
passwords, set a real hostname, restrict the exposed ports, and back up the
named volumes before relying on it.
How do I change the PHP version?
PHP_VERSION adds an extra Sury PHP you can select for sites.
ISP_PHP_VERSION must stay at the distro default (8.3 on
ubuntu:24.04, 8.2 on debian:12, 8.1 on ubuntu:22.04) because ISPConfig's OS
profile hardcodes that version for its own pools and sockets.
How do I upgrade ISPConfig or the container?
Data lives in named volumes, so a rebuild + docker compose up -d
recreates the container without touching sites, mail or the database. To bump
ISPConfig, raise ISP_CONFIG_VERSION and rebuild; the one-shot
install marker keeps it from re-running on an existing volume.
Why do I need privileged: true?
systemd-as-PID-1 needs SYS_ADMIN/NET_ADMIN and an
unconfined seccomp profile, and BIND/Fail2ban/pure-ftpd need networking and
kernel access. This is the cost of running a full server image; it's not
suitable for untrusted multi-tenant hosts.
What about Let's Encrypt certificates?
ISPConfig can manage Let's Encrypt per-site once the panel is up. The panel's own listener starts with a self-signed cert; you can replace it in the panel's SSL settings or front it with a reverse proxy.
Known issues
Panel 502: ISPConfig hardcodes the distro-default PHP
ISPConfig's OS profile picks one "default" PHP version per base (8.3 on
ubuntu:24.04) and writes its FPM pools + nginx sockets for that version. An
image that installed only a newer Sury PHP (e.g. 8.4) would leave
/var/lib/php8.3-fpm/apps.sock missing and the panel would 502.
Resolution: the Dockerfile installs
ISP_PHP_VERSION (the distro default) alongside
PHP_VERSION.
Panel 500: "temp is not writable" from Sury's php-fpm hardening
Sury's php-fpm systemd units ship ProtectSystem=full,
which mounts /usr read-only in the FPM worker's namespace. Since
ISPConfig lives in /usr/local/ispconfig and writes
interface/temp + server/temp, the panel's PHPIDS
check fails and the UI throws a 500 — while the same path is writable from the
CLI.
Resolution: the build drops a systemd override
ProtectSystem=no onto both php-fpm services.
Port 53 already in use (DNS)
On hosts running systemd-resolved, the stub listener on
127.0.0.53 can conflict with BIND's wildcard bind on port 53.
Disable it (systemctl disable --now systemd-resolved) or stop
mapping port 53 if you don't need container DNS.
First boot is slow
The first up -d downloads and compiles the whole ISPConfig stack
(several minutes). Subsequent boots are fast — only the one-shot install runs
on the first start.
Source
Everything lives in one repo: github.com/taavityrnpuu/ispconfig-docker. Open an issue there for bugs or questions.