Quick start
Shortest path from the delivery bundle to a working console. One Rocky / RHEL 9 host, one control node running ansible, one customer.env, one playbook run.
Before you start
| Item | Requirement |
|---|---|
| Target host | RHEL / Rocky / AlmaLinux 9 (8 works), 2 vCPU / 4 GB / 20 GB free under /var. Clean OS, never had FreeIPA on it |
| Hostname | hostname -f returns an FQDN (idm.corp.example) that resolves forward and reverse, and not to 127.0.0.1 / ::1 |
| Time | Within 5 minutes of the AD domain controller or upstream NTP. Kerberos rejects anything beyond that domain-wide |
| Ports | 80 / 443 / 389 / 636 / 88 / 464 / 53 / 123 free on the target |
| Control node | A second Linux box with ansible-core and gettext, ssh access to the target with passwordless sudo. Use all-in-one when there is no second box (below) |
| Bundle | idmatrix-host-<version>.tar.gz: playbook, console, licence layer, ansible collections and a 376 MB offline RPM repo. The target does not need internet |
Collect from the customer: the IPA FQDN, realm (upper case), domain (lower case), NetBIOS name (upper case); with AD, the AD domain, DC IP and an AD admin who can create trusts; the internal DNS address.
Install
Unpack, install collections
On the control node:
sha256sum -c idmatrix-host-<version>.tar.gz.sha256
tar xzf idmatrix-host-<version>.tar.gz && cd idmatrix-host-<version>
( cd collections && ansible-galaxy collection install -r requirements.yml )ansible-galaxy must run inside collections/: the requirements file lists bare tarball names resolved against the current directory.
All-in-one (control node is the target): run sudo ./bootstrap-controller.sh first. It installs ansible-core and gettext from the bundled rpms/ through a temporary repo without touching /etc/yum.repos.d.
Fill in customer.env
cd deploy && cp customer.env.example customer.env && chmod 600 customer.env
vi customer.envRequired changes:
| Field | Value |
|---|---|
ANSIBLE_CONNECTION | ssh for two-box; local for all-in-one |
IPA_HOSTNAME / IPA_HOST_ALIAS | Target FQDN, identical to hostname -f |
IPA_REALM / IPA_DOMAIN / IPA_NETBIOS | CORP.EXAMPLE / corp.example / CORP |
IPA_ADMIN_PASSWORD / IPA_DM_PASSWORD | Two different strong passwords, stored in a password manager after install. admin logs in to the console; Directory Manager is needed for backup, restore and replication maintenance and takes downtime to reset if lost |
SSH_USER / SSH_HOST / SSH_PRIVATE_KEY | Two-box only; leave empty for all-in-one |
IDM_LIC_SRC / IDM_WEBUI_DIST_SRC | <bundle>/license / <bundle>/dist |
IPA_SETUP_FIREWALLD / IPA_NO_NTP | true / false on bare metal |
Pick one DNS layout. The wrong one fails at forwarder validation:
| Situation | Setting |
|---|---|
| Reachable internal DNS | IPA_FORWARDERS=10.0.0.53 (quote multiple) |
| Air-gapped, no upstream | IPA_AUTO_FORWARDERS=false, IPA_FORWARDERS empty |
| Customer runs DNS, IPA must not | IPA_SETUP_DNS=false; add A / PTR / SRV records to the customer DNS by hand |
The default IPA_AUTO_FORWARDERS=true reads /etc/resolv.conf, which usually contains unreachable addresses. Do not leave it. All variables: Configuration.
Render, check connectivity
./render-inventory.sh
cd .. && ansible -i deploy/inventory.generated.yml all -m pingrender-inventory.sh turns customer.env into deploy/inventory.generated.yml and names any missing required field. Continue only after pong.
Run the playbook
ansible-playbook -i deploy/inventory.generated.yml deploy-ipaserver.yml10 to 20 minutes; run it under tmux. It registers the offline RPM repo, installs the FreeIPA server, runs ipa-server-install (directory, KDC, CA, DNS, adtrust), deploys the console and licence layer, and installs the daily backup timer. It ends with failed=0.
Do not rerun a failed install as is. Clean the target first with sudo ipa-server-install --uninstall -U, then start again from this step.
Verify
On the target:
sudo ipactl status # all 11 services RUNNING
curl -sk -o /dev/null -w '%{http_code}\n' https://<FQDN>/ipa/modern-ui/ # 200 or 301
cat /var/lib/idmatrix-license/status.json # valid:false is expected before activation
echo '<admin password>' | kinit admin && ipa pwpolicy-mod --minlength=9 # expect Forbidden
sudo systemctl list-timers idmatrix-backup.timer # NEXT is 02:30 tomorrow
chronyc sourcesThe fourth line matters most: writes must be refused before activation. If it succeeds, licence gating is not active; do not hand over. A broken gate shows no error, it just lets everything through.
Log in
Open https://<FQDN>/ipa/modern-ui/, accept the self-signed certificate, user admin, password IPA_ADMIN_PASSWORD. Use the FQDN; an IP address fails with ERR_CERT_AUTHORITY_INVALID.
The left navigation has five groups: Identity, Policy, Authentication, Network services, IPA Server. See the console overview.
After install
- Activate the licence: copy the host fingerprint from the "License Activation" page, send it to Reallysec, upload the
.licon the same page. The console is read-only until then. - With AD, set up the trust: run the prerequisite checklist, then
ipa trust-add. - Make Linux clients trust the IPA CA: export it with the bundled
export-ca.shand distribute to the client trust store. - Backups land in
/var/lib/ipa/backup/; an online data backup runs daily at 02:30. Off-host copies are the customer's job. - Store the
adminand Directory Manager passwords in a password manager.customer.envholds them in clear text; do not hand it to the customer or commit it.
Upgrade
Unpack the new bundle on the control node, keep the same customer.env, rerun the playbook. It is idempotent and only refreshes the console, licence layer and RPMs. Major FreeIPA upgrades go through ipa-server-upgrade; see Upgrade and backup.
The licence is bound to /etc/machine-id. Reinstalling the OS, moving to another machine or cloning a VM changes the fingerprint and invalidates the licence; it has to be reissued. Restoring a backup onto new hardware does the same.
Troubleshooting
| Symptom | Where to look |
|---|---|
ipa-server-install fails at DNS forwarder validation | IPA_FORWARDERS points at an unreachable address, or IPA_AUTO_FORWARDERS=true was left in |
| Install fails immediately on the hostname | hostname -f differs from IPA_HOSTNAME, or the name resolves to 127.0.0.1 / ::1 (check /etc/hosts and getent hosts <FQDN>) |
| Every write returns 403 after login | Not activated, or the licence lacks that module. Check valid and mods in status.json |
| Browser certificate error | IP address in the URL; use the FQDN |
kinit reports clock skew | chronyc sources; sync with the DC |
Rerun hangs in ipa-server-install | Previous attempt not cleaned up; ipa-server-install --uninstall -U first |
More under Troubleshooting.