Configuration files, which include other files, are not new. Placing those included files in sub-directories has also been an option since the beginning. Let's review use cases and see how to get the most out of this organization method.
Some people find a single configuration file to be the "simple" approach and a whole tree of files to be more complex. However, stop and think about how large some configuration files might grow, or how many different people or programs need to edit them. It really can be easier to allow each subproject to drop their configuration into their own file in a subdirectory. Recently, such as in
systemd documentation, these files are sometimes called "drop-in" files.
Over time, and especially in the past few years, the use of subdirectories in
/etc has increased. Two significant situations are driving this movement:
- Larger programs have split complex configuration files into multiple smaller files.
- Many other programs have become dependent on a single utility. Each of those utilities needs to manage a portion of the configuration.
Populate per package
Some of the first uses of
*.d directories I encountered were for logging and scheduling. Let's look at the
logrotate utility. The main configuration file is
/etc/logrotate.conf. It is not very complicated, but each file to be rotated needs to be specified. Each file may also need different configuration options. Instead of editing this single file each time an application is added or updated on the system, we separate the configuration for each application to a specific file.
$ grep ^include /etc/logrotate.conf include /etc/logrotate.d
The main configuration file includes all files in another directory. Files in the directory may originate from different RPM packages.
$ rpm -qf /etc/logrotate.d/aide aide-0.16-12.fc31.x86_64
$rpm -qf /etc/logrotate.d/rsyslog rsyslog-8.2002.0-1.fc31.x86_64
$ rpm -qf /etc/logrotate.d/chrony chrony-3.5-4.fc31.x86_64
The owner of each package knows what needs to be rotated and how frequently. They provide a configuration file specific to their application and add it to
logrotate.d directory during installation. It is also removed from
logrotate.d directory when the package is uninstalled from the system.
Other examples of this use case are scheduling with
cron in the
cron.d directory and authentication configuration with PAM in the
pam.d directory. By using separate files, the system administrator does not need to manage conflicting writes to a single file.
Organize by function
The Apache web server is an extensive program with many configuration options. Apache utilizes a
conf.d directory for organization. When I started with Apache, it was common to have a single server host multiple virtual sites. Each of those virtual hosts had its own configuration file. This approach allowed us to share the administration duties of the files as well as share the files on different systems during migration, recovery, and load balancing. Today, I see more cases where the configuration is separated by function.
Another factor is if the feature is installed as a separate module.
$ rpm -qf /etc/httpd/conf.d/ssl.conf mod_ssl-2.4.43-1.fc31.x86_64
ssl.conf configuration is made available only when the
mod_ssl package is installed. Other modules may also drop files into the
conf.d directory. Some applications, like the
mod_auth_kerb package, provide a sample in a
/usr/share/doc directory. It is up to the web administrator to create or manage the production files.
[ Need more help learning Linux? Free online course: Red Hat Enterprise Linux technical overview. ]
As I suggested with web configuration files, another use of separate configuration files is to make centralized management of these files easier, and only distribute relevant components to each managed node.
modules.d directory holds the configuration for kernel module settings and the
sysctl.d directory contains kernel tuning settings. These settings may only be needed on some systems, or may require hardware-specific settings. The settings can be organized by hardware, function, or a combination.
Configuration management programs can push just the relevant files to specific managed hosts or generate the files on each host based on a template. If you are distributing these files with a configuration management solution such as Ansible, use something like the
ansible_managed variable to include a comment indicating that the file is managed remotely.
Determine a name and location
While dot-d directories have common use cases for assisting with organization and distribution, there are many different ways of handling the includes. For each application or utility, we need to determine how best to name our files. Some configurations only recognize files with a specific extension, such as
.conf, while others reference all files in the directory.
man pages for the main configuration file, such as
man logrotate.conf, will usually describe the options. Still, I start by looking for an include statement in the configuration file.
When I search for includes, I see a variety of methods (formatted for readability):
$ grep ^include /etc/*conf krb5.conf : includedir /etc/krb5.conf.d/ ld.so.conf : include ld.so.conf.d/*.conf logrotate.conf : include /etc/logrotate.d rsyslog.conf : include(file="/etc/rsyslog.d/*.conf" mode="optional")
rsyslog configurations both expect included files to end in
.conf. The others look like they include all files, but further investigation may show a method for excluding files. For example,
man logrotate.conf shows that
taboopat can be used to filter out
.rpmnew, or other files that might result from versioning or updates. For the
krb5.conf file, there is both an
includedir directive. The man page indicates that the
includedir directive covers "all files within the directory whose names consist solely of alphanumeric characters, dashes, or underscores." It goes on to point out that files that start with a dot (.) are ignored.
Another consideration for included files is the read and merge order. I have seen a few that read in a random order, but most include files in the order they are found in the directory. If the sequence is particularly important, such as for modules or startup scripts, it is common to start the filenames with a number. Other naming standards such as "pre" or "post" are also common.
$ ls /etc/NetworkManager/dispatcher.d/ 04-iscsi 20-chrony no-wait.d pre-down.d pre-up.d
A few utilities may even have expansion symbols that help with managing and distributing centralized files. The
sudoers configuration is an example where a
%h represents the short form of the hostname.
The include line above specifies the configuration file for the current host, even if the directory contains other files. See
man sudoers for more examples.
Another hazard to using dot-d directories is that you may have to modify your syntax-checking commands.
In some cases, all of the configuration files must be checked at once. For example, with Apache, the
apachectl configtest command always checks the main configuration file, which can include other files. It uses default options. You can run the
httpd -t command with additional options. For example, there is an option to list all the included files.
$ httpd -t -D DUMP_INCLUDES Included configuration files: (*) /etc/httpd/conf/httpd.conf (59) /etc/httpd/conf.modules.d/00-base.conf (59) /etc/httpd/conf.modules.d/00-dav.conf
httpd command also takes an
-f option to specify a particular file. However, that file must pass all configuration checks, so checking an included file may not give the desired results. The following error occurs when checking the default
ssl.conf configuration file provided by the
$ httpd -t -f /etc/httpd/conf.d/ssl.conf AH00534: httpd: Configuration error: No MPM loaded.
Other applications do have methods of verifying the syntax for an included file. The
sudo configuration is normally modified by using the
visudo command so that a syntax validation can be done before saving and exiting. This utility edits the
/etc/sudoers file by default but also supports an
-f option to specify a different file.
$ sudo visudo -f /etc/sudoers.d/demo >>> /etc/sudoers.d/demo: syntax error near line 1 <<< What now? q Options are: (e)dit sudoers file again e(x)it without saving changes to sudoers file (Q)uit and save changes to sudoers file (DANGER!) What now? x
The same command also supports a
--check option to only validate a file without an edit.
$ visudo -c demo.sudo >>> demo.sudo: syntax error near line 1 <<< parse error in demo.sudo near line 1
Combine this with a validate option in your configuration management program to ensure that template expansions do not break a configuration file. There are samples in the documentation for the Ansible copy and template modules. I have also provided the following example from
ansible-doc template for
- name: Update sshd configuration safely, avoid locking yourself out template: src: etc/ssh/sshd_config.j2 dest: /etc/ssh/sshd_config owner: root group: root mode: '0600' validate: /usr/sbin/sshd -t -f %s backup: yes
A little digging through commented lines and man pages will help you get the most out of this organizational method by displaying distribution options, naming conventions, and syntax validation information.
Organizing configuration files into directories can make administration easier to manage and to delegate. Files may be organized by package or function and configuration management solutions such as Ansible can even benefit from smaller template files. You may need to standardize on file names and locations, and you may need to update file verification tools, but using a dot d folder to house multiple configuration files can save you a lot of effort.
[ Want to try out Red Hat Enterprise Linux? Download it now for free. ]