Server Basic Configuration
The source material covers basic Ubuntu Server configuration: hostname, domain, resolver, timezone, and locale. In this network, these settings apply in two places: the Proxmox host itself, and the base Ubuntu 24.04 container template that every service container is built from.
This page covers both. The Proxmox host configuration is done first, then the container template configuration which is applied once and inherited by every container provisioned from it.
Proxmox host: basic configuration
Connect to the Proxmox host via SSH or use the shell in the web interface (node > Shell).
Hostname
The hostname was set during installation. Verify it:
hostname -f
Expected output: server.yourdomain.net
If it needs changing:
hostnamectl set-hostname server.yourdomain.net
Hosts file
Ensure the /etc/hosts file is correctly configured for reliable FQDN resolution without depending on DNS:
sudo tee /etc/hosts << 'EOF'
127.0.0.1 localhost
127.0.1.1 server.yourdomain.net server
10.1.0.10 server.yourdomain.net server
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
Replace 10.1.0.10 with the actual static IP address assigned to the server on the Core VLAN.
Verify FQDN resolution:
hostname -f
# Expected: server.yourdomain.net
getent hosts server
# Expected: 10.1.0.10 server.yourdomain.net server
Timezone
timedatectl set-timezone Europe/London
timedatectl status
Verify the output shows Time zone: Europe/London (BST, +0100) (or GMT during winter) and NTP service: active.
Locale
The Proxmox host and all containers should use British English with UTF-8 encoding:
# Generate the required locales
locale-gen en_GB.UTF-8 en_US.UTF-8
# Set system-wide locale defaults
tee /etc/default/locale << 'EOF'
LANG=en_GB.UTF-8
LANGUAGE=en_GB:en
LC_ALL=en_GB.UTF-8
EOF
# Apply immediately
localectl set-locale LANG=en_GB.UTF-8
Verify:
locale
DNS resolver on the Proxmox host
The Proxmox host uses systemd-resolved for DNS. Configure it to use the internal Unbound resolver:
tee /etc/systemd/resolved.conf.d/internal-dns.conf << 'EOF'
[Resolve]
DNS=10.1.0.x
FallbackDNS=1.1.1.1
Domains=yourdomain.net
EOF
systemctl restart systemd-resolved
Replace 10.1.0.x with the internal Unbound resolver address. While Unbound is still being configured, use 1.1.1.1 as the primary DNS temporarily.
Verify resolution:
resolvectl status
resolvectl query google.com
Container template: base configuration
The container template is a configured Ubuntu 24.04 LXC container that serves as the starting point for every service container. Creating and configuring it once means every new container inherits the correct baseline configuration without manual repetition.
Download the Ubuntu 24.04 template
In the Proxmox web interface, navigate to node > local storage > CT Templates. Click Download from URL and select the Ubuntu 24.04 LXC template, or use the command line:
pveam update
pveam download local ubuntu-24.04-standard_24.04-2_amd64.tar.zst
Create the base container
In the web interface, click Create CT. Configure:
| Setting | Value |
|---|---|
| CT ID | 100 (or your preferred numbering scheme) |
| Hostname | base-template |
| Template | Ubuntu 24.04 standard |
| Root disk | 8GB on the SSD storage |
| CPU cores | 1 |
| RAM | 512MB |
| Network | vmbr0, VLAN tag 14 (Core VLAN), DHCP |
| DNS domain | yourdomain.net |
| DNS servers | 10.1.0.x |
Do not start the container yet.
Configure the base container
Start the container from the Proxmox web interface and open a console, or connect via SSH once it has an IP address.
Update packages
apt update && apt upgrade -y
apt autoremove -y
Hostname and hosts file
hostnamectl set-hostname base-template.yourdomain.net
tee /etc/hosts << 'EOF'
127.0.0.1 localhost
127.0.1.1 base-template.yourdomain.net base-template
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
Individual containers will update /etc/hostname and /etc/hosts with their own names after provisioning.
Timezone
timedatectl set-timezone Europe/London
Locale
apt install -y locales
locale-gen en_GB.UTF-8
tee /etc/default/locale << 'EOF'
LANG=en_GB.UTF-8
LANGUAGE=en_GB:en
LC_ALL=en_GB.UTF-8
EOF
Essential packages
Install a base set of packages that every container will need:
apt install -y \
curl \
wget \
gnupg \
ca-certificates \
apt-transport-https \
software-properties-common \
unattended-upgrades \
nano \
htop \
net-tools \
dnsutils \
mtr-tiny \
rsync \
postfix \
mailutils
The Postfix installation will ask for configuration type. Select Satellite system and set the relay host to [mail.yourdomain.net]:submission. The full Postfix null client configuration from the desktop section applies identically here.
Configure unattended upgrades
Enable automatic security updates:
tee /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::Package-Blacklist {};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Mail "root";
EOF
tee /etc/apt/apt.conf.d/20auto-upgrades << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
EOF
NTP configuration
tee /etc/systemd/timesyncd.conf.d/local.conf << 'EOF'
[Time]
NTP=10.1.0.1
FallbackNTP=0.uk.pool.ntp.org 1.uk.pool.ntp.org
EOF
systemctl restart systemd-timesyncd
timedatectl status
Disable IPv6 if not in use
For containers that do not need IPv6:
tee /etc/sysctl.d/99-disable-ipv6.conf << 'EOF'
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
EOF
sysctl --system
Remove this from containers that need IPv6.
Clean up before converting to template
Remove any temporary files, logs, and SSH host keys that should be unique per container:
# Clear logs
find /var/log -type f -exec truncate -s 0 {} \;
# Remove SSH host keys (generated fresh for each container)
rm -f /etc/ssh/ssh_host_*
# Clear bash history
history -c
cat /dev/null > ~/.bash_history
# Remove the machine ID (regenerated per container)
truncate -s 0 /etc/machine-id
# Clean package cache
apt clean
Convert to template
Shut down the container:
poweroff
In the Proxmox web interface, right-click the container and select Convert to Template. The container is now a template that can be cloned to create new containers.
Creating a new container from the template
To provision a new service container from the template:
In the Proxmox web interface, right-click the template and select Clone. Configure:
| Setting | Value |
|---|---|
| Mode | Full Clone |
| CT ID | Next available (e.g. 101, 102, 103…) |
| Hostname | Service-specific name (e.g. dns, mail, nextcloud) |
| Target Storage | SSD storage |
After cloning, update the hostname in the new container:
# In the new container
NEW_NAME="dns"
hostnamectl set-hostname ${NEW_NAME}.yourdomain.net
# Update /etc/hosts
sed -i "s/base-template/${NEW_NAME}/g" /etc/hosts
# Generate new SSH host keys
ssh-keygen -A
# Set a unique machine ID
systemd-machine-id-setup
This pattern, clone from template, update hostname, configure the service-specific packages, produces consistent containers with minimal repetition.
Reference: Proxmox container numbering
A consistent numbering scheme makes the container list readable at a glance:
| Range | Purpose |
|---|---|
| 100 | Base template |
| 101-109 | Core network services (DNS, NTP, monitoring) |
| 110-119 | Mail services |
| 120-129 | Web and application services |
| 130-139 | Nextcloud and file services |
| 140-149 | Media services |
| 150-159 | IoT and home automation |
| 200-299 | Virtual machines |
| 900-999 | Test and development containers |
This is a suggestion rather than a requirement. The important thing is consistency within the deployment.
The base template is worth getting right before cloning from it. Every service container inherits its configuration. A missing package or misconfigured timezone in the template means fixing the same issue in every container. Spend the time on the template. It pays back across every service deployment.