The Perfect Server on Debian 13

★ ★ ★ ★ ★ Not rated

Before you begin

This guide is for a new, empty Debian 13 VPS. It is not an in-place upgrade guide and must not be run on a server that already hosts sites, mail or a MariaDB installation.

Take a provider snapshot first. The installer reconfigures the server. You need public IPv4/IPv6, working outbound DNS and internet access. Choose a fully-qualified hostname such as server1.example.net, not a bare domain.
Prepare externally

Create A and, where applicable, AAAA records for the hostname. Set matching PTR/rDNS at the VPS provider before sending mail.

Do not mix stacks

Do not use this procedure where Apache, a mail stack, MariaDB or another hosting panel has already been configured.

The command below uses the maintained ISPConfig auto-installer for Debian 13. It builds the Perfect Server service stack without copying an old Debian 12 package list.

Become root

Connect by SSH as root, or start a full root login shell:

su --login

Confirm the base OS before continuing:

cat /etc/os-release
uname -m
id -u
Expected result VERSION_ID="13", an amd64 or arm64 architecture, and root user ID 0.

Configure hostname and DNS

Replace the example FQDN once, then copy the whole block. It adds the local hostname mapping only if it is missing.

export FQDN="server1.example.net"
export SHORT_HOSTNAME="${FQDN%%.*}"

hostnamectl set-hostname "$FQDN"
grep -qF "$FQDN" /etc/hosts || printf '127.0.1.1\t%s %s\n' "$FQDN" "$SHORT_HOSTNAME" >> /etc/hosts

hostname
hostname -f
getent hosts "$FQDN"
DNS checkpoint. Before continuing, ensure the hostname’s public A/AAAA record points at this VPS. Mail delivery and trusted TLS certificates depend on it.

Update Debian and reboot

apt update
apt -y full-upgrade
apt -y install ca-certificates curl wget gnupg lsb-release
systemctl reboot

Reconnect after the reboot and run:

hostname -f
apt update
apt -y autoremove
timedatectl status

Install Apache, mail, DNS, FTP and ISPConfig

Run this on the freshly prepared host. Apache is the default web server; the selected passive FTP range is opened in the next step.

wget -O - https://get.ispconfig.org | sh -s -- --use-ftp-ports=40110-40210 --unattended-upgrades

When asked for confirmation, type yes. The install sets up Apache, MariaDB, Postfix, Dovecot, Rspamd, BIND, Pure-FTPd, Jailkit, Roundcube, phpMyAdmin, ISPConfig and dependencies. At the end it prints the ISPConfig administrator and MariaDB root passwords.

Credential checkpoint. Put the generated passwords in a password manager immediately. Do not store them in shell history, source code, tickets, documentation or chat.
printf 'ISPConfig URL: https://%s:8080\n' "$(hostname -f)"
systemctl --no-pager --full status apache2 mariadb postfix dovecot pure-ftpd

Set the firewall

Set it only after installation, so the initial SSH session remains available. These are ports for a complete single-server setup.

ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 20,21/tcp
ufw allow 25,80,443,465,587,993,995,8080,8081/tcp
ufw allow 53/tcp
ufw allow 53/udp
ufw allow 40110:40210/tcp
ufw --force enable
ufw status numbered
One firewall owner. Use these UFW rules or equivalent rules through ISPConfig’s firewall module; do not maintain conflicting rule sets. If SSH uses a custom port, allow it before enabling UFW.

Do not expose MariaDB, Redis or Elasticsearch publicly. Keep them local-only unless a separately designed architecture requires access.

Verify the finished server

These commands are read-only checks:

systemctl is-active apache2 mariadb postfix dovecot pure-ftpd bind9
ss -lntup
apachectl configtest
mysqladmin ping
dig @127.0.0.1 localhost A
tail -n 50 /var/log/ispconfig/cron.log

Open https://server1.example.net:8080, sign in with the generated administrator credentials, and check the services under System → Server Services.

  • Create a test client and website; check its HTTP and HTTPS response.
  • Create a test database in ISPConfig and authenticate through phpMyAdmin.
  • Create a temporary FTP account and check document-root restriction.
  • Before real mail is sent, verify PTR/rDNS, SPF, DKIM and DMARC.

Add only what applications require

Multiple PHP versions

PHP 8.1, 8.4 and 8.5, PHP-FPM and ISPConfig registration.

Multiple MariaDB instances

A local-only compatibility database without weakening ISPConfig’s primary instance.

Redis and FFmpeg

Install Redis and FFmpeg when applications need them; keep Redis local.

Elasticsearch

Install from Elastic’s current official repository; retain authentication/TLS and bind it to loopback.

Troubleshooting and safe recovery

Do not repeatedly rerun the installer over a partly configured server. First inspect the log; restore the pre-install snapshot if a clean retry is needed.

tail -n 200 /tmp/ispconfig-ai/var/log/ispconfig.log
systemctl --failed
journalctl -p err -b --no-pager
apachectl configtest

For diagnostics on a new server only, add --debug to the installer command. Its log is written to /tmp/ispconfig-ai/var/log/ispconfig.log.

Done. After the checks pass, the VPS is ready for ISPConfig clients, sites, mail domains, DNS zones and migrations.

Install the application runtimes and libraries

The ISPConfig base installer does not replace this application-specific layer. The following blocks install the required PHP versions and extensions for the current CMS estate, plus Redis, FFmpeg and Elasticsearch.

Repository checkpoint. PHP 8.1 and 8.5 are not Debian 13’s default PHP branch. This uses the Sury PHP repository, which must be treated as a managed third-party production repository and kept patched.

8.1 Add the PHP repository

install -d -m 0755 /usr/share/keyrings
wget -qO /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ trixie main" > /etc/apt/sources.list.d/sury-php.list
apt update
apt-cache policy php8.1 php8.4 php8.5

8.2 Install PHP 8.1, 8.4 and 8.5 with the CMS extension set

apt -y install \
  php8.1-bcmath php8.1-bz2 php8.1-cli php8.1-common php8.1-curl php8.1-fpm php8.1-gd php8.1-igbinary php8.1-imagick php8.1-intl php8.1-mbstring php8.1-mysql php8.1-opcache php8.1-readline php8.1-redis php8.1-xml php8.1-zip \
  php8.4-bcmath php8.4-bz2 php8.4-cli php8.4-common php8.4-curl php8.4-fpm php8.4-gd php8.4-igbinary php8.4-imagick php8.4-intl php8.4-mbstring php8.4-mysql php8.4-opcache php8.4-readline php8.4-redis php8.4-xml php8.4-zip \
  php8.5-bcmath php8.5-bz2 php8.5-cli php8.5-common php8.5-curl php8.5-fpm php8.5-gd php8.5-igbinary php8.5-imagick php8.5-intl php8.5-mbstring php8.5-mysql php8.5-opcache php8.5-readline php8.5-redis php8.5-xml php8.5-zip

systemctl enable --now php8.1-fpm php8.4-fpm php8.5-fpm
# Verify BCMath for exact tax and money calculations.
php8.1 -r 'echo bcadd("1.20", "2.30", 2), PHP_EOL;'
php8.4 -r 'echo bcadd("1.20", "2.30", 2), PHP_EOL;'
php8.5 -m

8.3 Register the versions in ISPConfig

In System → Additional PHP Versions, add the three FPM records. The paths are version-specific: FPM pool /etc/php/VERSION/fpm/pool.d, socket /run/php/phpVERSION-fpm.sock, ini /etc/php/VERSION/fpm/php.ini and CLI binary /usr/bin/phpVERSION. Use the full PHP article for the exact per-version fields, then select the runtime per site under Sites → Website → Options.

8.4 Install Redis and FFmpeg

apt -y install redis-server ffmpeg
systemctl enable --now redis-server
systemctl is-active redis-server
redis-cli ping
ffmpeg -version

8.5 Install and contain Elasticsearch

Elasticsearch is intentionally installed from Elastic’s official APT repository. It is an application backend, not a public endpoint.

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/9.x/apt stable main" > /etc/apt/sources.list.d/elastic-9.x.list
apt update
apt -y install elasticsearch

printf '%s\n' '-Xms1g' '-Xmx1g' > /etc/elasticsearch/jvm.options.d/heap.options
printf '%s\n' 'http.host: ["127.0.0.1", "::1"]' 'transport.host: ["127.0.0.1", "::1"]' >> /etc/elasticsearch/elasticsearch.yml
systemctl daemon-reload
systemctl enable --now elasticsearch
systemctl --no-pager status elasticsearch
ss -lntp | grep -E ':(9200|9300)'
Elasticsearch security. The Debian package enables security material on first start. Keep its generated credentials and CA material in the password manager, and use HTTPS plus authentication from the application. Never add ports 9200 or 9300 to the public firewall.

Complete Perfect Server service coverage

The ISPConfig installer builds the base configuration. This chapter makes every component explicit, verifies it, and adds packages that are useful or required for the same functional coverage as a traditional manual Perfect Server installation.

Safe to re-run. All package-install commands below are idempotent. They complete a fresh auto-installed server; do not use them to retrofit an unrelated existing mail or web stack.

9.1 SSH, editors and clock synchronization

apt -y install openssh-server nano vim-nox chrony rkhunter binutils
systemctl enable --now ssh chrony
systemctl is-active ssh chrony
chronyc tracking
rkhunter --version

Keep SSH on port 22 during initial deployment. Password authentication and root login can be hardened only after a named administrator account and tested SSH key access exist; otherwise remote access can be lost.

9.2 System mail, Postfix and Dovecot

Postfix accepts and submits mail, while Dovecot provides IMAP, POP3, LMTP and sieve. ISPConfig writes the virtual-domain and mailbox configuration; do not hand-edit its generated virtual user files.

systemctl enable --now postfix dovecot
systemctl is-active postfix dovecot
postconf -n
doveconf -n
ss -lntp | grep -E ':(25|465|587|110|143|993|995)'
Mail is not ready merely because services run. Before accepting real mail, set PTR/rDNS at the provider and publish SPF, DKIM and DMARC for every mail domain. Create mail domains and mailboxes in ISPConfig, not directly in Postfix or Dovecot.

9.3 Rspamd and ClamAV

Rspamd provides modern spam filtering. ClamAV is installed for malware scanning when the server’s capacity and mail policy require it.

apt -y install rspamd clamav clamav-daemon
systemctl enable --now rspamd clamav-daemon
systemctl is-active rspamd clamav-daemon
rspamadm configtest
freshclam --version

Use the Rspamd web interface only from a trusted network. Do not publish it directly to the internet.

Apache, TLS, FTP and disk quotas

10.1 Apache and PHP-FPM

Apache vhosts and per-site PHP-FPM pools are generated by ISPConfig. Confirm the syntax and enabled modules before adding websites.

systemctl enable --now apache2
apachectl configtest
apachectl -M | grep -E 'rewrite|ssl|http2|proxy_fcgi'
systemctl is-active apache2

10.2 Let’s Encrypt

The ISPConfig installer uses acme.sh by default. Create the website in ISPConfig, enable Let’s Encrypt for that site, and ensure its public A/AAAA record already points at this server. Port 80 must be reachable for HTTP validation.

test -x /root/.acme.sh/acme.sh && /root/.acme.sh/acme.sh --version
systemctl list-timers --all | grep -Ei 'acme|cert'
curl -I http://server1.example.net/

Use --use-certbot only when deliberately migrating an existing Certbot-based setup. Do not run both ACME clients for the same certificate.

10.3 Pure-FTPd and passive ports

systemctl enable --now pure-ftpd
systemctl is-active pure-ftpd
ss -lntp | grep -E ':(21|40110|40210)'
grep -R 40110 /etc/pure-ftpd /etc/default 2>/dev/null || true

Create FTP users through ISPConfig. They are SQL-backed virtual users, not normal entries in /etc/passwd, and their files must be owned by the target site’s web user and client group.

10.4 Quotas

Traditional filesystem quotas require a quota-capable ext4/XFS mount and boot-time mount options. Do not force-enable them inside a ZFS-backed or restricted LXC VPS: use the provider’s storage quota instead. On a supported bare-metal or VM filesystem, install quota, configure the filesystem mount options, reboot, run quotacheck, then enable quotas before switching quota support on in ISPConfig.

BIND, web statistics and Jailkit

11.1 BIND DNS

BIND is installed for local resolution and optional ISPConfig-managed DNS zones. Installing BIND does not require changing your public nameservers. Keep the current DNS provider authoritative until a planned nameserver migration.

systemctl enable --now bind9
named-checkconf
dig @127.0.0.1 localhost A
dig @127.0.0.1 . NS

Create DNS zones in DNS → DNS Zone only when this server will be authoritative for them. Limit recursion to local/trusted clients; never run an unrestricted public recursive resolver.

11.2 Webalizer, AWStats and GoAccess

apt -y install webalizer awstats goaccess
webalizer --version
awstats.pl -version
goaccess --version

Enable a statistics application per website in ISPConfig. Log processing and report paths are generated by the panel; do not expose raw access logs through a document root.

11.3 Jailkit

apt -y install jailkit
command -v jk_init
jk_init --version

Enable jailed shell only for users that need it. Test each user’s deployment tools inside the jail before granting production access.

Fail2ban, phpMyAdmin and Roundcube

12.1 Fail2ban

apt -y install fail2ban
systemctl enable --now fail2ban
fail2ban-client status
fail2ban-client status sshd

Use a local /etc/fail2ban/jail.d/*.local file for custom policy; never edit packaged jail.conf. Add a tested recovery IP only when you understand the security impact.

12.2 phpMyAdmin

test -f /usr/share/phpmyadmin/config.inc.php
apachectl -S | grep -i phpmyadmin || true
curl -kI https://127.0.0.1/phpmyadmin/

Access phpMyAdmin at https://server1.example.net/phpmyadmin/ after its TLS certificate is ready. Restrict access with an ISPConfig-protected vhost, VPN, IP allow-list, or an additional HTTP authentication layer. Normal website databases are managed through ISPConfig; the separate legacy MariaDB is administered outside ISPConfig as described in the MariaDB article.

12.3 Roundcube

test -d /var/lib/roundcube -o -d /usr/share/roundcube
systemctl is-active postfix dovecot
curl -kI https://127.0.0.1/roundcube/

Access webmail at https://server1.example.net/roundcube/. A successful Roundcube login requires an existing ISPConfig mailbox and working Dovecot authentication; it is not a replacement for DNS and mail-delivery validation.

Operations, backups and final acceptance

13.1 Updates and health checks

apt update
apt -y upgrade
systemctl --failed
df -h
free -h
journalctl -p err -b --no-pager
tail -n 100 /var/log/ispconfig/cron.log

Apply normal OS security updates regularly. Before major version upgrades, take a provider snapshot and verify ISPConfig’s documented upgrade procedure.

13.2 Backups are mandatory

ISPConfig can schedule per-client website and database backups, but a production server also needs an off-server backup target and tested restore process. Define retention, encryption, access control, monitoring and restoration ownership before onboarding production data.

  • Restore one website and one database to a non-production location.
  • Restore one mailbox and verify IMAP access.
  • Confirm backups are stored outside the VPS and encrypted where appropriate.
  • Alert when a scheduled backup or ISPConfig cron job fails.

13.3 Final service checklist

  • Apache, MariaDB, Postfix, Dovecot, Pure-FTPd, BIND, Rspamd, Fail2ban and ISPConfig cron processing are active.
  • UFW exposes only the intended web, mail, DNS, FTP and panel ports.
  • All public website and mail hostnames resolve to the intended server and have valid certificates.
  • PTR/rDNS, SPF, DKIM and DMARC are validated before mail is used in production.
  • PHP 8.1/8.4/8.5, Redis, FFmpeg and Elasticsearch were tested by the applications that use them.
  • Databases, virtual FTP accounts, web roots and mailboxes are created through their intended management path.
Perfect Server complete. The base server and the application runtime layer are now documented as one reproducible Debian 13 build, with separate articles for the two intentional compatibility exceptions: multiple PHP versions and legacy MariaDB.
0.0
★ ★ ★ ★ ★
0 reviews
5 ★
0 %
4 ★
0 %
3 ★
0 %
2 ★
0 %
1 ★
0 %

Add a comment

There's nothing here.

No comments have been posted here yet.