Why GLPI directory layout decides how safely you can upgrade
If your GLPI configuration, keys, uploaded files, logs and plugins live inside the application source tree, every upgrade becomes a risky file replacement. The source tree is the code that ships with a GLPI release. Writable data is everything GLPI changes while it runs: database connection settings, the glpi.key and glpicrypt.key encryption keys, uploaded documents, log files and marketplace plugins. Keeping that data outside the source tree means the application files can be replaced without overwriting the things you cannot regenerate. This matters for any production install, and for any install you expect to move to GLPI 11 or 12.
The update procedure in the GLPI installation docs starts with a backup of the database, the files and the config directory, explicitly including glpi.key and glpicrypt.key. The docs then describe replacing the application files and running php bin/console db:update. Losing or mismatching those keys can leave encrypted data unreadable, so the layout should make the config directory easy to identify, back up and restore on its own. Confirm the exact file names and backup steps against the GLPI update documentation for the version you are running before you write a runbook.
Plugin handling is the other reason layout matters. Since GLPI 11.0, plugins are suspended when a new version is detected and must be reactivated after major updates. Teams should decide before the first upgrade where marketplace plugins live, who approves them, and how their versions are tracked against the target release. Ask your plugin authors and your own change process to confirm compatibility, because a suspended plugin can change ticket routing, forms or inventory behavior until someone reactivates it. A layout that separates plugins, configuration and uploads gives you a clear rollback point for each.
Which directories to move and where each one goes
The configuration directory holds the settings that define how this GLPI instance connects to its database and handles secrets. Moving it out of the source tree means that replacing the application files during an upgrade cannot overwrite these values. The encryption keys live here too, and losing them makes encrypted data unreadable, so this location needs the same backup discipline as the database.
- Database connection settings: Host, database name and service credentials are the first values a new deployment needs, and only the service account should be able to read them.
- Encryption keys: The update procedure names
glpi.keyandglpicrypt.keyas files to back up before any change. Store copies in your secrets management system and in an offline backup. - Downstream and local overrides:
downstream.phppoints GLPI to the external configuration location, andlocal_define.phpholds constants that override defaults. Confirm the file names and constants for your version before you write them. - Restricted write access: Make the directory readable by the web service user and keep it read-only at runtime where the design allows, so changes to database targets require an administrator.
Confirm the exact locations and supported constants in the GLPI update documentation for your installed version before you change anything.
The files directory stores content users upload or the application generates, such as ticket documents, attachments and some exports. It usually grows fastest of all the writable areas, and it is the area most likely to need shared storage once you run more than one web node. Placing it outside the web tree and the source tree keeps user content out of the code deployment and makes its backup schedule independent of application releases.
- Growth and capacity: Attachments accumulate over time, so size the volume for retention rules, not for day one.
- Backup scope: Include this directory in every backup set alongside the database, because a database restore without its matching files leaves broken references.
- Permissions: The web service user needs read and write access. Other local users should have no access, and direct web access to the directory should be blocked.
- Multi-node access: If several web servers serve the same instance, all of them must see the same files, which usually means a shared file system. Confirm the supported approach for your version.
- Ownership changes: Keep the owner and group consistent after restores, or uploads will fail silently for some users.
Before go-live, ask the vendor or check the documentation to confirm the default path for your version and how to relocate it, then test an upload and a restore end to end.
The log directory records application events, errors and some activity that operators use for troubleshooting and audit trails. Keeping logs outside the source tree means they survive upgrades and can be rotated and shipped on their own schedule. Logs can also contain personal data about users and tickets, so their location and access need the same care as the data they describe.
- Separate retention: Set rotation and retention for logs independently of backups, so a noisy error loop does not fill the volume that holds the database.
- Write access: The web and scheduled task users need to write here, and nobody else should be able to read or modify the files.
- Central collection: If your organization runs a central log platform, forward these files from the host with an agent you already operate, and confirm which events the instance writes.
- Sensitive content: Treat log files as data. Restrict access to administrators who need them and review what is recorded for personal data.
- Permission drift: Log files created by a different user, such as a manual console command run as root, can block the web service from writing. Check ownership after maintenance.
Confirm the log location, the logging levels available and the rotation approach for your installed version, and test that errors still reach the file after you change the path.
The marketplace directory holds plugins installed through the GLPI interface or copied in by administrators. Placing it outside the core source tree keeps third-party code separate from the application, so a core update replaces only GLPI's own files. Plugins are also the part of the instance most likely to break during an upgrade, which makes their location and lifecycle worth planning before the first install.
- Suspension after updates: According to the GLPI installation documentation, plugins are suspended once GLPI detects a new version, and they must be reactivated after major updates. Plan a check of every plugin in the upgrade runbook.
- Write window: The web user needs write access to install or update plugins. Consider restricting write access outside maintenance windows, then reverting the setting afterwards.
- Code review: Treat each plugin as third-party code. Record its source, version and checksum, and review it before it reaches production.
- Version pinning: Keep a list of plugin versions tied to each GLPI version so a rollback has a known target.
- Backups: Include the plugin directory and its configuration in the backup set, since a restored database may reference plugins that are missing on disk.
Confirm the marketplace path, whether it can be relocated and the plugin activation steps for your GLPI version before you change the layout, because both the path and the upgrade behavior change between major releases.
Layout options and when each fits
This table compares the default layout, moving only the config directory, and moving config, files, logs and the marketplace out of the source tree, plus two deployment shapes that change the answer. Read each row from left to right: what leaves the source tree determines what an update replaces and what a backup must capture. The main takeaway is that moving the key files and data directories out of the tree is what makes updates and restores predictable.
| Layout | What moves out of the tree | Upgrade and backup effort | Best fit |
|---|---|---|---|
| Default layout | Nothing. Config, files, logs and marketplace stay inside the GLPI source tree. | Each update replaces application files, so data directories must be preserved or copied by hand before and after. | Trials and lab installs only, since production data sits in the path that updates overwrite. |
| Config directory only | Configuration and key files, located through downstream.php and local_define.php. | Keys survive file replacement, but files, logs and marketplace still need manual handling at every update. | Single servers with modest file volumes and no need to share storage. |
| Config, files, logs and marketplace | All four directories, each pointed to from downstream.php or local_define.php. | Replace the source tree and keep the external directories. Back up the database and every external directory, including key files. | Single servers with a dedicated data volume, and the base for shared or containerized setups. |
| Shared storage across web nodes | Files, logs and marketplace on a mount every node reads, with config shared as well. | All nodes must run the same version and be updated together. Back up the shared mount once, not per node. | Several front ends behind a load balancer, with storage every node can reach. |
| Container with official image | Config, files and marketplace on mounted volumes. Confirm the exact paths against the image documentation. | Update by image tag while volumes persist. Back up volumes, database and keys together. | Docker or container platforms where the image is replaced and state lives in volumes. |
How to move GLPI directories out of the source tree
This sequence relocates GLPI's configuration, files directory, logs and plugins outside the web-served application tree so that the application code can be replaced during upgrades without touching data. It ends with a tested instance and a rehearsed upgrade path that your team can repeat.
Back up database, files and config
The administrator takes a full database dump, a copy of the GLPI files directory and a copy of the config directory, including glpi.key and glpicrypt.key. Store the keys separately from the database dump, because the database alone cannot decrypt stored credentials without them. The step is done when you can restore the backup to a scratch host and read the restored instance's configuration and encrypted fields.
Create directories outside the web root
The platform engineer creates separate directories for config, files, logs and plugins on a path the web server cannot serve, then sets ownership to the web server user and restricts access to that user and the administrator group. Keep the GLPI application tree and these data paths on different parent directories so a future replacement of the application code cannot remove them. The step is done when the web server user can write to each directory and a direct HTTP request for a path inside them returns a denied or not found response.
Point GLPI at the new paths
Using the GLPI documentation for your version, the administrator creates downstream.php in the application's inc directory to define the path to the config directory, then creates local_define.php in the config directory to set the files, logs and plugins paths. Confirm the exact constant names and file locations for your release in the installation documentation before editing, since they are version-specific. The step is done when the GLPI setup check or administration page loads without path errors and reports the new locations.
Move existing data into the new layout
The administrator copies the existing files directory, log files and installed plugins into the new locations, preserving ownership and permissions, and then removes the originals from the source tree only after the next checks pass. Move plugins with their directory structure intact so GLPI can detect them. The step is done when a file-count and checksum comparison between old and new locations matches, and no GLPI path still resolves inside the application tree.
Set file permissions for each directory
The administrator applies the narrowest workable permissions: the config directory should be readable by the web server user and not writable by it after setup, the files directory and logs directory should be writable by the web server user, and plugin directories should be readable with write access limited to the deployment account. Record the expected modes in your build runbook so they can be checked after each change. The step is done when a scripted permission check against that runbook reports no differences.
Verify with login, upload and log write
The tester signs in with a test account, uploads a file attached to a ticket or asset, and triggers an action that writes to the log directory, such as a failed login. Confirm each action succeeds and the resulting file appears in the new files and logs paths, not the old ones. The step is done when all three checks pass and the web server access log shows no successful request for the data paths.
Rehearse an upgrade on a copy
The engineer restores the backup to a staging host using the new layout, replaces the application files with the target release, and runs the database update command from the GLPI update documentation. Plugins are suspended after a new version is detected, so reactivate them only after confirming each one supports the target release. The step is done when the upgraded staging instance passes the login, upload and log checks, and the team has recorded the sequence and time it took to repeat it.
File permissions for each directory
Each GLPI directory has a different job, so each needs a different permission. The web server user should read the code and configuration it needs, write only where GLPI stores runtime data, and have no write access to the application code it runs. Confirm the exact modes against your distribution and PHP-FPM pool user before you apply them.
Config directory
The config directory holds database connection settings and the key files such as glpi.key and glpicrypt.key. The web user needs read access so GLPI can start, but the files should not be readable by other local users or served over HTTP. Losing or changing the key files can make stored secrets unreadable, so restrict access and back them up under the same controls as the database. Confirm the owner and mode on each key file in your own environment.
Files directory
The files directory stores uploads, attachments and generated documents, so the web user needs write access here. It must sit outside the web root so that stored documents are only delivered through GLPI's own access checks, not by a direct URL. Check that your web server configuration denies direct requests to this path, and that the directory is excluded from any world-readable shared mount.
Log directory
The log directory receives GLPI and PHP-level entries that you will need during incident review and upgrades. The web user needs write access, but the logs themselves should not be readable by unrelated accounts because they can contain user names and request details. Set up log rotation so the directory does not fill the disk, and confirm the rotation user can read and rename files that the web user writes.
Marketplace directory
The marketplace directory holds plugins installed through the GLPI interface. Keep it read-only to the web user during normal operation, and grant write access only for the window in which you install or update a plugin, then remove it. This limits what a compromised web process can plant in the application. Confirm with your change process who opens and closes that window.
Source tree
The application code should be owned by a deployment account and readable by the web user, but not writable by it where your layout allows. Read-only code makes unauthorized changes harder and makes it easier to show which files changed during an update. Where the layout forces writes, document each path and review it during hardening. Confirm which paths GLPI needs to write in your release before you lock the rest.
Update and maintenance access
Upgrades replace application files and run database updates, so the account doing that work needs more access than the web user for a short period. Keep that account separate from the PHP-FPM or web server user, and revert permissions after the update. Plugins are suspended after a new version is detected, so plan reactivation as part of the same change window.
How the layout changes GLPI upgrades and plugin reactivation
Moving configuration, the files directory, logs and the marketplace out of the source tree makes GLPI upgrades safer because the application files can be replaced without touching data or secrets. The update procedure in the GLPI installation documentation expects you to back up the database, the files and the config directory, including glpi.key and glpicrypt.key, then replace the application files and run php bin/console db:update. If downstream.php points to an external config directory and local_define.php holds the path overrides, the code swap is a simple replacement of the source tree. Confirm that both files survive the swap and that the paths they reference still resolve on the new release.
Plugins need separate attention. Since GLPI 11.0, plugins are suspended after a new version is detected and must be reactivated after major updates. Plan a reactivation pass into the change window, and check each plugin against its own release notes before enabling it, since a plugin built for one major version may not load on the next. Test after any path move: log in, open a ticket with an attachment to confirm the files directory is writable, check that the log directory receives entries, open the marketplace page, and run the automatic actions once to confirm the cron user can read the config directory.
A rollback needs the same inventory. Keep the pre-upgrade database dump, a copy of the old application tree, and the external config and files directories as they were before db:update ran. Note that a database rollback is needed if the schema changed, so the old application tree alone is not enough. Ask your vendor or the plugin authors to confirm which plugin versions support the target release, and rehearse the restore on a non-production copy before the change window.
Security and operational risks of directory placement
Moving GLPI's config, files, logs and plugins out of the web tree removes several common exposure paths, but each move creates its own failure mode. The cards below pair each risk with the control that addresses it and the check that proves the control still works after updates, restores and multi-server changes.
Keys stored under the web root
The glpi.key and glpicrypt.key files protect encrypted data in the database, and a copy reachable through the browser would expose that material to anyone who can guess its path. Control: keep the config directory outside the document root, and point GLPI at it through downstream.php or local_define.php so the web server never needs to serve it. Verify: request the config path and the key file names directly over HTTP and confirm each returns a denial or a not-found response.
Uploaded files served directly
Ticket attachments, documents and inventory files land in the files directory, and a web server that maps that path to a URL can serve executable or HTML uploads to other users. Control: place the files directory outside the public directory, deny web access to it, and let GLPI stream downloads through its own permission checks. Verify: upload a test file to a ticket, then fetch its storage path directly and confirm the request fails.
World-readable configuration
A config file readable by every local account exposes database credentials and encryption settings to anyone who gets a shell on the host. Control: set the web server user as the owner of the config and key files, give them mode 0640 or stricter, and keep the deployment user separate from the runtime user. Verify: list the files as the runtime user and as an unrelated local account, and confirm the second account cannot read them.
Log growth filling disks
GLPI writes application and SQL logs to a logs directory, and a debug setting or a failing integration can grow those files faster than anyone reads them. Control: place logs on a volume with its own capacity alert, rotate them with logrotate, and keep debug logging off outside investigations. Verify: check the logs directory size after a week of normal activity and confirm a rotation rule runs and that the alert fires at the threshold you set.
Backups that miss the key files
A database and files backup restores ticket data, yet without glpi.key and glpicrypt.key the encrypted values in the database cannot be read after recovery. Control: include the config directory in every backup job and store the key files with the same retention and access rules as the database dump. Verify: restore a backup to a clean host, start GLPI, and confirm stored credentials and encrypted fields still decrypt.
Shared storage permission drift
In multi-server installs, the files and plugins directories often sit on shared storage, and ownership or mode changes on one node can break uploads or plugin loading on the others. Control: define one owner and group for the shared paths, mount them with the same options on every node, and reapply permissions from a single deployment step. Verify: run the same write and read test as the web user from each server and compare results after every update.
Questions teams ask before moving GLPI directories
What does moving GLPI directories cost in effort, and what drives it?
The effort depends mostly on how much GLPI has been customized and how the instance is run today. The move itself is a bounded task: relocating the config directory, the files directory, logs and the marketplace, then pointing GLPI at them through downstream.php and local_define.php. The cost grows with the number of installed plugins (each one may write to paths or assume locations that change), the volume of existing file attachments and documents, and whether GLPI runs in a container, where storage is usually a volume mount, or on bare metal, where the web tree and permissions are managed by hand. Ask any partner for a quote that lists each of these inputs separately, along with the test copy, the validation steps and the rollback plan.
Can our own team move GLPI directories without a partner?
Often yes, if you have someone comfortable with Linux file permissions, the web server configuration and PHP, and you can run a full copy of the instance first. The work requires knowing which user the web server and PHP-FPM run as, how to read and write the config directory and files directory safely, and how to confirm that the application still starts and that attachments still load after the change. Teams without that skill set usually want a partner to review the plan or do the work on a staging copy. Either way, the first step is a test copy built from a recent backup, not the production system.
How long does a GLPI directory move take, and what sets the duration?
No duration is supplied for this work, so confirm it in a quote rather than assuming one. The main variables are the number of plugins to test, the size of the files directory (copying large volumes takes time and needs a maintenance window), the number of web servers or containers sharing the storage, and how many environments you must validate, such as staging, production and any disaster recovery copy. Ask the partner to state which of these they have assumed and which steps are blocked until a window is available.
What should we provide to a partner before they quote the move?
Give the partner a clear picture of the current installation so the quote reflects real inputs. Useful items include the GLPI version and PHP version, the web server and whether it runs in Docker or on a Linux host, the database type and version, the list of installed plugins with their versions, the current paths for config, files, logs and marketplace, the size of the files directory, and the backup method in use. Also provide access to a non-production copy, the backup and recovery expectations, and the maintenance windows you can accept.
How do directory changes interact with a GLPI upgrade?
Plan the directory move as a separate, tested change, not something folded into an upgrade. The GLPI update procedure requires backing up the database, the files and the config directory, including glpi.key and glpicrypt.key, before replacing application files and running php bin/console db:update. If the config and files paths move at the same time, the backup and restore steps must still point at the correct locations. Since GLPI 11.0, plugins are suspended after a new version is detected and must be reactivated after major updates, so check plugin compatibility on the target version before the production change, and confirm the upgrade sequence with the vendor documentation for your exact target release.
Which file permissions must be right after the move, and what breaks if they are not?
The web server user must be able to read the GLPI application code and the public directory, and must be able to write to the files and log locations GLPI uses at runtime, while the config directory should be readable by the application but not writable by the web user during normal operation. If permissions are too broad, sensitive keys and settings are exposed. If they are too narrow, uploads fail, logs stop being written and the marketplace cannot install or update plugins. Test each path after the change by uploading a document, triggering a log entry, and checking a plugin action, then confirm the exact ownership model against the official install documentation for your version.
What is the main risk when moving GLPI directories, and how do we limit it?
The main risk is losing access to encrypted data or existing attachments because a key or path was not carried over correctly. Keys such as glpi.key and glpicrypt.key must stay with the config directory and be included in every backup. Limit the risk by taking a full backup before the change, rehearsing the move on a copy, recording the old and new paths, keeping the previous layout available for rollback until the new one has been checked, and agreeing in writing who signs off the validation results.
How DeployOpen scopes and delivers GLPI directory layout work
DeployOpen starts every GLPI directory layout engagement with a written, fixed scope that names the paths to move, the web root that will serve only the public directory, and the systems that depend on each path. The scope lists which files will hold downstream.php and local_define.php, where the config directory and the files directory will live, which log and marketplace locations will be used, and which service accounts will own each path. Before any change, we ask for the current install path, the PHP and database versions in use, the web server configuration, and the backup method. Those inputs decide whether the work is a fresh layout or a move of an existing instance, and they drive the quote far more than the number of users does.
Delivery follows a set sequence in your own infrastructure: back up the database, the files and the config directory, including glpi.key and glpicrypt.key, then relocate directories, set ownership and permissions for each path, and verify that the web server still serves only the public directory. Each change is tested against a non-production copy first, and the plugin state is checked afterward, since GLPI 11.0 suspends plugins when it detects a new version. DeployOpen documents the final paths, permissions, cron and log locations in a runbook that your operations team keeps. Handover covers a walkthrough and a verification checklist that your staff can repeat after future updates.
Ongoing work such as upgrades to later GLPI releases, plugin reviews and permission audits can be placed under a retainer, which is billed on an agreed cadence rather than per incident. Ask any partner, including DeployOpen, to confirm in writing what the retainer covers, how long a response may take, and who holds administrative access after handover. Confirm with your own security team which backup retention and encryption standards apply to the config and key files before the scope is signed, because those choices belong to your organization and shape the work.

