Skip to content

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/glpi recommended 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 update refreshes package lists; apt upgrade installs security updates.

  • wget/curl/unzip are utility tools used later for downloads and extraction.

  • software-properties-common provides add-apt-repository (useful for PPAs).

  • ca-certificates/gnupg ensure 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_php or php-fpm.

  • a2enmod rewrite — enables URL rewriting (GLPI uses front-controller index.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:

sudo systemctl status apache2
curl -I http://localhost

Alternative: use php-fpm + nginx for higher concurrency; requires different config.


5. Install MariaDB

sudo apt install -y mariadb-server
sudo systemctl enable --now mariadb

Why MariaDB: MySQL/MariaDB is GLPI’s supported relational DB. MariaDB is compatible and frequently packaged with Ubuntu.

Secure MariaDB:

sudo mysql_secure_installation

Follow prompts:

  • set root password, remove anonymous, disallow remote root, remove test DB — reduces attack surface.

Verification:

sudo mysql -e "SELECT VERSION();"

Notes: production DB tuning (innodb_buffer_pool_size, max_connections) happens later.


6. Database configuration

6.1 Load timezone tables

sudo mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql mysql

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)

sudo mysql -uroot -p

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.

  • curlAPI calls/external integrations.

  • gd — image generation (inventory images, graphs).

  • imap — mail retrieval for ticket creation.

  • ldapLDAP/Active Directory authentication.

  • mysqlDB 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:

php -m | grep -E 'apcu|gd|ldap|mysqli|redis|mbstring|intl'

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:

sudo mkdir -p /etc/glpi
sudo mkdir -p /var/lib/glpi
sudo mkdir -p /var/log/glpi

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 640 for 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:

nano /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 GLPI public folder (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 to index.php for 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:

sudo systemctl restart apache2
# or for php-fpm:
sudo systemctl restart php8.3-fpm

14. Web installer

Open browser to http://SERVER-IP/ (or domain).

Steps:

  1. Choose language.

  2. Accept license.

  3. Click InstallGLPI will validate requirements (missing PHP modules will be shown).

  4. Enter DB connection: host=localhost, database=glpi, user=glpi, password=....

  5. Wait for installer to create tables and default data.

  6. 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/glpi and /var/lib/glpi.


15. Post-installation actions

  1. Remove installer (prevent re-run or exposure):
sudo rm -rf /var/www/html/glpi/install
  1. Change default admin password — mandatory to avoid compromise.

  2. Enable HTTPS (see section 17).

  3. Review plugins — only install trusted plugins.

  4. 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).

sudo crontab -u www-data -e

16.2. Add the Cron Entry (Choose One Method)

Recommended: PHP CLI (most stable)

*/5 * * * * /usr/bin/php /var/www/html/glpi/front/cron.php

Alternative: curl (commonly used for HTTP cron)

*/5 * * * * /usr/bin/curl -s http://127.0.0.1/glpi/front/cron.php >/dev/null 2>&1

Alternative: wget

*/5 * * * * /usr/bin/wget -q -O - http://127.0.0.1/glpi/front/cron.php >/dev/null 2>&1

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>&1 prevents 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:

  sudo -u www-data php /var/www/html/glpi/front/cron.php

Then refresh Automatic Actions and verify "Last run" changed.

  • Method 3: Check System Logs
  grep CRON /var/log/syslog | grep www-data

This shows cron execution events.

    1. Common Problems & How to Check Cron job silently fails

Check cron logs:

  grep CRON /var/log/syslog

Permission issues

Ensure www-data can read GLPI files:

  sudo -u www-data ls /var/www/html/glpi

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):

sudo apt install -y certbot python3-certbot-apache sudo certbot --apache

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:

sudo certbot renew --dry-run

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:

sudo mkdir -p /opt/backups
sudo chown root:root /opt/backups
sudo chmod 755 /opt/backups

18.2 Manual DB dump

mysqldump -u glpi -p glpi > /opt/backups/glpi_$(date +%F).sql

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:

sudo chmod +x /usr/local/bin/backup-glpi.sh

Security note: store DB password securely. Example ~/.my.cnf for automated dump:

~/.my.cnf (owner root, mode 600):

[client]
user=glpi
password=StrongPassword123!

Then mysqldump runs without -p argument.

18.4 Cron schedule

Edit root or appropriate system crontab:

sudo crontab -e

Add:

0 2 * * * /usr/local/bin/backup-glpi.sh >> /var/log/glpi/backup.log 2>&1

Why 02:00? off-peak window; adjust to local operations.

18.5 Offsite & integrity

  • Copy backups offsite (SFTP, object storage).

  • Use gpg to 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:

sudo apt install -y libapache2-mod-php
sudo systemctl restart apache2

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:

sudo systemctl status apache2
sudo systemctl status mariadb

Check PHP modules:

php -m

Check Apache config syntax:

sudo apachectl configtest

View GLPI logs:

sudo ls -l /var/log/glpi sudo tail -F /var/log/glpi/*.log

MySQL test connection:

mysql -u glpi -p -D glpi -e "SELECT COUNT(*) FROM glpi_users;"

Final operational notes

  • Protect /etc/glpi/local_define.php and 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.