GLPI 11 Installation on Ubuntu Server 24.04¶
1. Introduction¶
GLPI is a robust, open-source ITSM (IT Service Management) and IT Asset Management platform designed to help organisations manage their hardware and software assets, track incidents and requests, handle inventory, contracts, and licensing, and support workflows in a structured way.
This guide covers the installation of GLPI version 11.x on an Ubuntu Server 24.04 LTS, using a classical LAMP stack (Apache2 + MariaDB + PHP 8.3). The installation is designed for production use, and emphasises:
-
Security – hardened settings, proper user privileges, minimal exposure to risk.
-
FHS compliance – separate directories for configuration (
/etc/glpi), data (/var/lib/glpi), and logs (/var/log/glpi) to align with the Filesystem Hierarchy Standard, making backups, management, and maintenance cleaner. -
Repeatable commands – every step is provided with exact shell commands so you can reproduce the installation reliably.
-
“Why” explanations – for each significant command or configuration change, this guide explains not just how, but why you do it. That way you’re not just following steps, but understanding the underlying reasoning.
This installation guide also references the official GLPI documentation, in particular the Ubuntu installation tutorial available at the official Help Center: Install GLPI on Ubuntu – GLPI Project Help Center You are encouraged to refer to the official documentation for updates, alternate configurations, or plugin-specific instructions. This guide builds on the official steps, expanding them with enterprise-grade best practices, including directory relocation, cron automation, backup strategy, and production tuning.
2. System requirements¶
-
OS: Ubuntu Server 22.04 or 24.04 — stable, widely supported.
-
CPU: 2 vCPU min — GLPI background jobs and web UI need CPU cycles.
-
RAM: 4 GB minimum; 8+ GB recommended when inventory/large dataset present.
-
Storage: 50 GB+; separate volume for
/var/lib/glpirecommended for growth. -
Network: port 80/443 reachable for web and Let's Encrypt.
-
Users: sudo user on server.
Why: realistic resource sizing prevents slow UI, queue backlog, and DB timeouts.
3. Update system¶
sudo apt update && sudo apt -y upgrade
sudo apt install -y wget curl unzip software-properties-common ca-certificates gnupg
Why each part:
-
apt updaterefreshes package lists;apt upgradeinstalls security updates. -
wget/curl/unzipare utility tools used later for downloads and extraction. -
software-properties-commonprovidesadd-apt-repository(useful for PPAs). -
ca-certificates/gnupgensure secure HTTPS and repository signature verification.
Notes: run this before adding external repos or installing major packages.
4. Install Apache¶
sudo apt install -y apache2
sudo a2enmod rewrite headers env dir mime
sudo systemctl enable --now apache2
Why Apache:
-
Apache is stable and well-supported by GLPI. It integrates with
mod_phporphp-fpm. -
a2enmod rewrite— enables URL rewriting (GLPI uses front-controllerindex.php). -
headers— allows setting security HTTP headers (HSTS, X-Frame-Options). -
env, dir, mime— common modules for environment vars, directory handling, and MIME types.
Verification:
Alternative: use php-fpm + nginx for higher concurrency; requires different config.
5. Install MariaDB¶
Why MariaDB: MySQL/MariaDB is GLPI’s supported relational DB. MariaDB is compatible and frequently packaged with Ubuntu.
Secure MariaDB:
Follow prompts:
- set root password, remove anonymous, disallow remote root, remove test DB — reduces attack surface.
Verification:
Notes: production DB tuning (innodb_buffer_pool_size, max_connections) happens later.
6. Database configuration¶
6.1 Load timezone tables¶
Why: GLPI and scheduled tasks may need timezone conversions; MySQL timezone tables must exist to allow CONVERT_TZ().
6.2 Create DB and user (charset explained)¶
Then:
CREATE DATABASE glpi CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'glpi'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON glpi.* TO 'glpi'@'localhost';
GRANT SELECT ON mysql.time_zone_name TO 'glpi'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Why utf8mb4: supports full Unicode incl. 4-byte chars (emojis). Why separate user: principle of least privilege and easier audits. Why SELECT ON mysql.time_zone_name: allows the app user to read timezone list if needed by GLPI.
Security note: never use weak password; rotate credentials and consider storing them in secret manager.
7. Install PHP 8.3 + required extensions¶
sudo apt install -y php php-{apcu,cli,common,curl,gd,imap,ldap,mysql,xmlrpc,xml,mbstring,bcmath,intl,zip,redis,bz2} \
libapache2-mod-php php-soap php-cas
Why PHP 8.3: current supported runtime; GLPI 11 expects modern PHP. Why each extension (short):
-
php— base runtime. -
php-cli— run console commands (cron jobs). -
libapache2-mod-php— if using mod_php (alternatively use php-fpm). -
apcu— local opcode/object cache for performance. -
curl— API calls/external integrations. -
gd— image generation (inventory images, graphs). -
imap— mail retrieval for ticket creation. -
ldap— LDAP/Active Directory authentication. -
mysql— DB driver. -
xml/xmlrpc— XML handling for plugins and legacy integrations. -
mbstring— multi-byte string handling (UTF-8). -
bcmath— arbitrary precision math for some plugins. -
intl— localization and collation. -
zip,bz2— archive handling for attachments and plugin uploads. -
redis— optional cache backend (requires Redis server). -
php-soap— SOAP API integration. -
php-cas— CAS SSO support.
Note about php-fpm: for higher throughput, install php8.3-fpm and configure Apache proxy_fcgi instead of libapache2-mod-php.
Verify installed modules:
8. Download GLPI¶
cd /var/www/html
sudo wget https://github.com/glpi-project/glpi/releases/download/11.0.2/glpi-11.0.2.tgz
sudo tar -xvzf glpi-11.0.2.tgz
Why verify checksum: protects against tampered downloads. Check the SHA256/MD5 published on the release page. Example if checksum provided:
sha256sum glpi-11.0.2.tgz # compare with value on GitHub release page
Note: keep original tarball for reference/rollback.
9. Prepare FHS-compliant directories¶
Why FHS: keep configuration outside webroot (/etc), data in /var/lib, logs in /var/log. This improves security and backup separation.
Commands:
Move default folders:
sudo mv /var/www/html/glpi/config /etc/glpi
sudo mv /var/www/html/glpi/files /var/lib/glpi
# if package includes _log inside files
sudo mv /var/lib/glpi/_log /var/log/glpi 2>/dev/null || true
Why move config: prevents direct access via web server if misconfigured. Why move files: keeps uploads and binaries separate from codebase.
Important: After moving, GLPI must be able to locate these directories — see downstream/local_define.
10. GLPI configuration files¶
10.1 downstream.php (in webroot) — purpose¶
This file instructs GLPI to include config from /etc/glpi.
Create:
sudo tee /var/www/html/glpi/inc/downstream.php > /dev/null <<'EOF'
<?php
define('GLPI_CONFIG_DIR', '/etc/glpi/');
if (file_exists(GLPI_CONFIG_DIR . '/local_define.php')) {
require_once GLPI_CONFIG_DIR . '/local_define.php';
}
EOF
Why: keeps application code untouched and loads environment-specific config outside webroot.
10.2 local_define.php (in /etc/glpi) — map directories¶
Create:
sudo tee /etc/glpi/local_define.php > /dev/null <<'EOF'
<?php
define('GLPI_VAR_DIR', '/var/lib/glpi');
define('GLPI_DOC_DIR', GLPI_VAR_DIR);
define('GLPI_CACHE_DIR', GLPI_VAR_DIR.'/_cache');
define('GLPI_CRON_DIR', GLPI_VAR_DIR.'/_cron');
define('GLPI_GRAPH_DIR', GLPI_VAR_DIR.'/_graphs');
define('GLPI_LOCAL_I18N_DIR', GLPI_VAR_DIR.'/_locales');
define('GLPI_LOCK_DIR', GLPI_VAR_DIR.'/_lock');
define('GLPI_PICTURE_DIR', GLPI_VAR_DIR.'/_pictures');
define('GLPI_PLUGIN_DOC_DIR', GLPI_VAR_DIR.'/_plugins');
define('GLPI_RSS_DIR', GLPI_VAR_DIR.'/_rss');
define('GLPI_SESSION_DIR', GLPI_VAR_DIR.'/_sessions');
define('GLPI_TMP_DIR', GLPI_VAR_DIR.'/_tmp');
define('GLPI_UPLOAD_DIR', GLPI_VAR_DIR.'/_uploads');
define('GLPI_INVENTORY_DIR', GLPI_VAR_DIR.'/_inventories');
define('GLPI_THEMES_DIR', GLPI_VAR_DIR.'/_themes');
define('GLPI_LOG_DIR', '/var/log/glpi');
EOF
Why: instructs GLPI where data and logs live after we moved them.
Tip: back up /etc/glpi/local_define.php and treat it as part of configuration management.
11. Set permissions¶
Commands:
sudo chown root:root /var/www/html/glpi/ -R
sudo chown -R www-data:www-data /etc/glpi /var/lib/glpi /var/log/glpi
sudo chown -R www-data:www-data /var/www/html/glpi/marketplace 2>/dev/null || true
Permission modes:
sudo find /var/www/html/glpi/ -type f -exec chmod 644 {} \;
sudo find /var/www/html/glpi/ -type d -exec chmod 755 {} \;
sudo find /etc/glpi -type f -exec chmod 640 {} \;
sudo find /etc/glpi -type d -exec chmod 750 {} \;
sudo find /var/lib/glpi -type f -exec chmod 640 {} \;
sudo find /var/lib/glpi -type d -exec chmod 750 {} \;
Why:
-
Web application files: owned by root, readable by web user — reduces accidental modification.
-
Runtime/data/configs: owned by
www-data(webserver user) so GLPI can write caches, uploads, logs. -
Use
640for config files so only owner (www-data) and group (www-data) can read; root can access as well. -
Avoid
777— security risk.
Pitfalls: incorrect ownership causes 500 errors, inability to upload files, or cron failures.
12. Apache VirtualHost¶
Create /etc/apache2/sites-available/glpi.conf:
and then input:
<VirtualHost *:80>
ServerName glpi.example.local
DocumentRoot /var/www/html/glpi/public
<Directory /var/www/html/glpi/public>
Require all granted
Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
</Directory>
# Security headers (simple baseline)
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "no-referrer-when-downgrade"
Header always set X-XSS-Protection "1; mode=block"
ErrorLog ${APACHE_LOG_DIR}/glpi_error.log
CustomLog ${APACHE_LOG_DIR}/glpi_access.log combined
</VirtualHost>
Enable site and reload:
sudo a2enmod headers rewrite
sudo a2dissite 000-default.conf
sudo a2ensite glpi.conf
sudo systemctl reload apache2
Explain directives:
-
ServerName— hostname for virtual host. -
DocumentRoot— point to GLPIpublicfolder (front controller). -
<Directory>Require all granted— allow web access to that directory. -
Options -Indexes— prevent directory listing in case index missing. -
RewriteRule— rewrite incoming URLs toindex.phpfor routing. -
Security headers — reduce clickjacking, MIME sniffing, and some XSS risks.
Note: if using php-fpm, VirtualHost needs ProxyPassMatch/SetHandler configuration.
13. PHP runtime configuration¶
Edit /etc/php/8.3/apache2/php.ini (or FPM pool if using php-fpm).
Recommended changes — edit /etc/php/8.3/apache2/php.ini:
File upload & memory limits:
sudo sed -i 's/^upload_max_filesize.*/upload_max_filesize = 20M/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's/^post_max_size.*/post_max_size = 20M/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's/^memory_limit.*/memory_limit = 256M/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's/^max_execution_time.*/max_execution_time = 60/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's/^max_input_vars.*/max_input_vars = 5000/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's|^date.timezone.*|date.timezone = Asia/Jakarta|' /etc/php/8.3/apache2/php.ini
| Parameter | Value | Why |
|---|---|---|
upload_max_filesize | 20M | Limit attachment upload size |
post_max_size | 20M | Must be >= upload_max_filesize |
memory_limit | 256M | Enough for imports and plugins |
max_execution_time | 60 | Prevent hanging scripts; increase for large imports |
max_input_vars | 5000 | Prevent large form truncation |
date.timezone | Asia/Jakarta | Match server timezone |
Opcache (performance):
sudo sed -i 's/^opcache.enable.*/opcache.enable=1/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's/^opcache.memory_consumption.*/opcache.memory_consumption=128/' /etc/php/8.3/apache2/php.ini
sudo sed -i 's/^opcache.max_accelerated_files.*/opcache.max_accelerated_files=10000/' /etc/php/8.3/apache2/php.ini
Why opcache: drastically improves PHP performance and reduces CPU. Why max_input_vars: GLPI forms can be large (inventory). If truncated, data loss occurs.
After editing:
14. Web installer¶
Open browser to http://SERVER-IP/ (or domain).
Steps:
-
Choose language.
-
Accept license.
-
Click Install → GLPI will validate requirements (missing PHP modules will be shown).
-
Enter DB connection:
host=localhost,database=glpi,user=glpi,password=.... -
Wait for installer to create tables and default data.
-
Log in with default admin credentials (change immediately).
Default users (after install):
| User | Password |
|---|---|
| glpi | glpi |
| tech | tech |
| normal | normal |
| post-only | postonly |
Tips:
-
If installer complains about missing PHP modules, install them and reload the page.
-
If permission errors occur, recheck ownership (
www-data) and write permissions of/etc/glpiand/var/lib/glpi.
15. Post-installation actions¶
- Remove installer (prevent re-run or exposure):
-
Change default admin password — mandatory to avoid compromise.
-
Enable HTTPS (see section 17).
-
Review plugins — only install trusted plugins.
-
Backup local_define.php — include in config management.
Why: reduces attack surface and secures production instance.
16. Cron Setup (Updated for GLPI 11.x)¶
GLPI uses background tasks to process notifications, inventory imports, mail receivers, database cleanup, and plugin jobs. In GLPI 11, all automatic actions are executed through the entry point front/cron.php, not via bin/console tasks:run (removed in GLPI 11).
This step ensures GLPI’s internal scheduler runs automatically.
16.1. Create Cron Job for www-data¶
GLPI must run cron jobs under the same user as the web server (typically www-data on Ubuntu).
16.2. Add the Cron Entry (Choose One Method)¶
Recommended: PHP CLI (most stable)
Alternative: curl (commonly used for HTTP cron)
Alternative: wget
Explanation
-
*/5 * * * *→ run every 5 minutes. This is frequent enough for notifications and inventory processing without overloading the system. -
Use full path to PHP/curl/wget Cron runs in a limited environment, so full paths avoid “command not found” errors.
-
Why
front/cron.php? In GLPI 11, this is the only entry point used to trigger Automatic Actions. The old CLI commands (tasks:run,tasks:status, etc.) were removed. -
Silent output Using
>/dev/null 2>&1prevents cron from sending emails every time it runs.
16.3. How to Verify Cron Is Working¶
- Method 1: Check via Web Interface (most reliable)
In GLPI, go to:
Setup → Automatic Actions
Check:
Last run → timestamp should update every 5 minutes
Execution mode = CLI
Status = OK
If timestamps are updating → cron is working.
- Method 2: Manual Cron Trigger
Run cron.php manually as www-data:
Then refresh Automatic Actions and verify "Last run" changed.
- Method 3: Check System Logs
This shows cron execution events.
-
- Common Problems & How to Check Cron job silently fails
Check cron logs:
Permission issues
Ensure www-data can read GLPI files:
PHP limitations
If tasks stop mid-process (large inventory imports, email processing):
Increase:
memory_limit
max_execution_time
max_input_vars
Edit /etc/php/8.3/apache2/php.ini then restart Apache.
17. HTTPS (Let’s Encrypt)¶
Install Certbot (Apache plugin):
Certbot will:
-
obtain a certificate using ACME (port 80 must be reachable),
-
configure Apache virtual host to use the certificate,
-
set up renewal cron/systemd job.
Test renew:
Notes:
-
If server behind firewall, allow inbound 80/443.
-
For automation in air-gapped environments, use internal CA and configure Apache with cert/key.
18. Backup strategy¶
What to back up:
-
/etc/glpi(configuration files) -
/var/lib/glpi(uploads, documents, caches if needed) -
/var/log/glpi(app logs) -
Database (mysqldump: schema + data)
Directory for backups (example): /opt/backups — keep on separate volume if possible.
18.1 Create backup directory¶
If you get:
bash: /opt/backups/glpi_2025-11-24.sql: No such file or directory
it means /opt/backups doesn't exist. Create and secure it:
18.2 Manual DB dump¶
Note: -p will prompt for password; avoid password in command line in production. Use .my.cnf or secrets manager.
18.3 Automated backup script (robust)¶
Create /usr/local/bin/backup-glpi.sh:
sudo tee /usr/local/bin/backup-glpi.sh > /dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
DATE=$(date +%F)
BACKUP_DIR="/opt/backups"
DB_USER="glpi"
# DB_PASSWORD can be placed in ~/.my.cnf for security
DB_NAME="glpi"
RETENTION_DAYS=14
mkdir -p "${BACKUP_DIR}"
chmod 750 "${BACKUP_DIR}"
# Database dump
mysqldump -u "${DB_USER}" -p"${DB_PASSWORD:-}" "${DB_NAME}" > "${BACKUP_DIR}/glpi_${DATE}.sql"
# Files backup (only changed files could be optimized)
tar -czf "${BACKUP_DIR}/glpi_files_${DATE}.tar.gz" -C /var/lib glpi
tar -czf "${BACKUP_DIR}/glpi_config_${DATE}.tar.gz" -C /etc glpi
# Rotate old backups
find "${BACKUP_DIR}" -type f -mtime +${RETENTION_DAYS} -delete
EOF
Make executable:
Security note: store DB password securely. Example ~/.my.cnf for automated dump:
~/.my.cnf (owner root, mode 600):
Then mysqldump runs without -p argument.
18.4 Cron schedule¶
Edit root or appropriate system crontab:
Add:
Why 02:00? off-peak window; adjust to local operations.
18.5 Offsite & integrity¶
-
Copy backups offsite (SFTP, object storage).
-
Use
gpgto encrypt backups if stored on public cloud. -
Verify DB dump integrity periodically (attempt restore on staging).
19. Troubleshooting¶
19.1 PHP files are downloaded instead of executed¶
Cause: Apache not configured to pass PHP to interpreter (mod_php missing or php-fpm misconfigured). Fix:
Or configure Apache to use php-fpm (ProxyPassMatch).
19.2 Missing PHP extensions reported by GLPI installer¶
Cause: necessary PHP modules not installed. Fix: install missing package (e.g., php-ldap, php-imap) and restart Apache.
19.3 Permission errors (500 or cannot upload)¶
Cause: wrong owners/modes on /etc/glpi, /var/lib/glpi. Fix: ensure www-data owns runtime dirs and files are not world-writable.
19.4 Cron jobs not executing¶
Cause: wrong crontab user, PATH issues, or permission. Fix: use full binary paths in cron (e.g., /usr/bin/php), run as www-data for GLPI tasks, check cron service.
19.5 mysqldump error: No such file or directory¶
Cause: target directory doesn’t exist. Fix: create backup directory and set permissions (see section 18.1).
19.6 Slow performance under load¶
Possible causes: insufficient innodb_buffer_pool_size, missing opcache, lack of redis cache. Fix: tune MariaDB innodb_buffer_pool_size to ~60–70% of available RAM (if dedicated DB server), enable opcache, consider Redis for cache.
20. Useful commands¶
Check services:
Check PHP modules:
Check Apache config syntax:
View GLPI logs:
MySQL test connection:
Final operational notes¶
-
Protect
/etc/glpi/local_define.phpand backup it into config management (Ansible/GitOps) but do not commit secrets to code repos. -
Test restores regularly: restore DB + files to staging to ensure backup validity.
-
Monitor cron logs and queue backlog; large inventories or plugins can cause task backlog if cron interval too long.
-
Consider external monitoring (Prometheus/Alerting) for CPU, DB latency, and disk usage.