Rspamd employs the Universal Configuration Language (UCL) for its configuration. You can find an extensive description of the UCL format in this document. Additionally, Rspamd introduces a range of variables and macros to enhance UCL’s functionality.
UCL adopts the JSON data model, although Rspamd’s documentation frequently refers to sections
. Consider these sections as straightforward sub-objects of the main object. For instance, the following two definitions are equivalent in both UCL
and JSON
syntax:
section "foo" {
opt = 10;
}
vs
{
"section": {
"foo": {
"opt": 10
}
}
}
UCL also offers support for the .include
macro, a feature heavily utilized in Rspamd’s configuration. This macro allows the inclusion of other files, enabling the definition of override or merge strategies, establishment of new element priorities, and other beneficial operations. Throughout Rspamd’s configuration, nearly all sections are followed by two or three include directives. The following overview outlines how the include macro is employed in Rspamd, while further elaboration can be found in the Macros Support section of the UCL documentation.
.include(param=value,param=value) "filename"
Param/value arguments represent options, often referred to as policies, that are applicable to the included file.
The “priority” policy dictates the hierarchy for overwriting values during the inclusion process. Elements with higher priority take precedence over those with lower priority.
The “duplicate” policy specifies the behavior when encountering two objects with the same name in both files. Employing the “merge” value for the “duplicate” policy results in key merging from the included file into the current file. (For additional values, consult the Macros Support notes.)
This is how included files are processed:
Here is an example of how .include
is used to achieve a desired configuration.
# fileA.conf
obj {
key = 1;
subobj {
subkey = 2;
}
}
.include(duplicate=merge,priority=1) "fileB.conf"
# fileB.conf
obj {
key = 2;
nkey = 1;
subobj {
subkey = 3;
nsub = 1;
}
}
will form the following configuration:
obj {
key = 2; # fileB overrides fileA
nkey = 1; # added from fileB
subobj {
subkey = 3; # fileB overrides fileA
nsub = 1; # added from fileB
}
}
Typical section in Rspamd (where section is replaced with an actual section name):
section {
default_key = "value";
subsection {
foo = "bar";
}
.include(try=true,priority=5) "${DBDIR}/dynamic/section.conf"
.include(try=true,priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/section.conf"
.include(try=true,priority=10) "$LOCAL_CONFDIR/override.d/section.conf"
}
If you want to add or redefine some of those default values, you can use a local.d/section
file:
# local.d/section.conf
new_key = "new_value";
subsection {
foo = "nobar";
}
Note: If an include directive is situated within a section {}
block, it’s essential that the included local.d/override.d files do not possess an identical section {}
wrapper. This would inadvertently lead to nested blocks like section { section{} }
. Conversely, files referred to by include directives outside of a section must explicitly delineate the sections they define, following a pattern like section{} section{}
where the second section either overrides or merges with the first.
Rspamd introduces a range of valuable variables designed for use in configuration files, denoted as ${VAR}
or simply as $VAR
. These variables are dynamically replaced with corresponding values during runtime. However, it’s important to note that nested variables such as ${ VAR1_${VAR2} }
are NOT supported.
$PREFIX/etc/rspamd/
Configuration files that are installed or updated with Rspamd are not meant to be modified directly by the user. Instead, these files should be overridden in site-specific configuration files. You can find more information on this process in the quickstart page.
However, it’s important to note that packaging typically avoids overwriting configuration files during upgrades if they have been modified by the user. For a smooth transition when upgrading to a new version of Rspamd, be sure to carefully review the migration notes for any incompatible configuration changes.
The Rspamd configuration process begins with the file $CONFDIR/rspamd.conf
. This file contains several settings and includes references to other files, which in turn might include additional files. The complete configuration is a compilation of all processed files, following the order in which they are encountered.
Each core Rspamd file incorporates an include to the local.d
folder for local overrides, as well as another include to the override.d
folder for final overrides. To better understand this architectural approach, you can refer to the related FAQ and other resources on the topic.
The rspamd.conf
file commences by incorporating common.conf
:
.include "$CONFDIR/common.conf"
Within common.conf
, a Lua script that includes rules is specified as $RULESDIR/rspamd.lua
. This Lua configuration file is pivotal in Rspamd, as it loads and runs numerous other Lua programs as modules.
Note: The variable $RULESDIR
typically corresponds to a path like /usr/share/rspamd/rules
.
Subsequently, additional files are included to establish rules, set rule priorities, and define Rspamd actions.
lua = "$RULESDIR/rspamd.lua"
.include "$CONFDIR/metrics.conf"
.include "$CONFDIR/actions.conf"
.include "$CONFDIR/groups.conf"
.include "$CONFDIR/composites.conf"
.include "$CONFDIR/statistic.conf"
.include "$CONFDIR/modules.conf"
.include "$CONFDIR/settings.conf"
Each of these .conf
files defines a specific section, along with corresponding .include
files that permit local settings to override each section.
actions.conf
and groups.conf
.actions.conf
(without a separate document yet) delineates score thresholds for specific action types.groups.conf
(also without a separate document yet) introduces a singular “group” section housing multiple symbol groups. Each group incorporates .include
directives pointing to files that detail symbols linked to those groups. (For more, see).conf
files located in the modules.d folder. For instance, configurations for the RBL module are specified in “/modules.d/rbl.conf”. The modules.conf
file primarily serves to .include
all of these module configuration files..include(try=true) "$LOCAL_CONFDIR/rspamd.conf.local"
.include(try=true,priority=10) "$LOCAL_CONFDIR/rspamd.conf.local.override"
.include(try=true,priority=10) "$LOCAL_CONFDIR/rspamd.conf.override"
modules {
path = "${PLUGINSDIR}";
fallback_path = "${SHAREDIR}/lua"; # Legacy path
try_path = "${LOCAL_CONFDIR}/plugins.d/"; # User plugins
}
The modules section establishes paths for directories or specific files. When a directory is specified, all files in that folder with a .lua
suffix are loaded as Lua plugins. (The directory path is treated as a *.lua
shell pattern).
Returning to rspamd.conf
, it encompasses a global options section, followed by the configuration for logging.
options {
pidfile = "$RUNDIR/rspamd.pid";
.include "$CONFDIR/options.inc"
.include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/options.inc"
.include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/options.inc"
}
.include(try=true; duplicate=merge) "$CONFDIR/cgp.inc"
.include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/cgp.inc"
logging {
type = "file";
filename = "$LOGDIR/rspamd.log";
.include "$CONFDIR/logging.inc"
.include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/logging.inc"
.include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/logging.inc"
}
Ultimately, a workers section (code not provided here) is outlined, utilizing the aforementioned section "foo" {}
syntax, to define worker types such as normal, controller, rspamd_proxy, and fuzzy.
Jinja stands as a contemporary and design-friendly templating language for Python, modelled after Django’s templates. Lupa is a Jinja2 template engine implementation written in Lua and supports Lua syntax within tags and variables.
Beginning with version 1.9.1, Rspamd introduces support for Jinja templates combined with Lua code within Rspamd UCL configuration files. This functionality extends beyond static assignments and .include
directives, allowing the implementation of logic and data transformations. Notably, Rspamd employs a specific syntax for variable tags, namely {=
and =}
, to prevent conflicts with Lua’s use of {{
and }}
, which might otherwise signify “a table within a table” in Lua.
Templating offers the advantage of concealing sensitive values from configuration files, achieved by placing them into environment variables. Rspamd automates the reading of environment variables that begin with the RSPAMD_
prefix, subsequently pushing them onto the env
variable. For instance, RSPAMD_foo=bar
would translate to env.foo="bar"
in the templates.
The env
variable also contains the following information:
ver_major
- major version (e.g. 1
)ver_minor
- minor version (e.g. 9
)ver_patch
- patch version (e.g. 1
)version
- full version as a string (e.g. 1.9.1
)ver_num
- numeric version as a hex string (e.g. 0x1090100000000
)ver_id
- git ID or release
if not a git buildhostname
- local hostnameYou can also add values, not merely plain strings but any Lua objects, like tables, by specifying additional environment files with the --lua-env
command line argument. The specified Lua program file will be read by the root
user if the Rspamd main process starts as root and then drops privileges.
The Lua program file (or files) when specified multiple times should return a table as a single possible outcome. For example:
return {
var1 = "value",
var2 = {
subvar1 = "foo",
subvar2 = true,
}
}
You can then use the variables as follows in config files:
{% if env.var2.subvar2 %}
foo = {= env.var1 =};
baz = {= env.var2.subvar2 =};
{% endif %}
You can also use this for secure storage of passwords. This code sample would be used in a config file, and demonstrates many details for using Jinja.
# local.d/controller.inc
{% if env.password %}
password = "{= env.password|pbkdf =}"; # Password is encrypted using `catena` PBKDF
{% endif %}
Please note that the pipe symbol |
serves the purpose of conveying the password to a Jinja filter, which facilitates further processing. Within Rspamd, the pbkdf
filter is available and is utilized to encrypt the password using the PBKDF standard, specifically employing the Catena hashing scheme.
With this enhancement, as of version 1.9.1, your config files should be Jinja safe. However, this also implies that there should be no special sequences like {%
or {=
anywhere in your configuration, other than for Jinja. If you do require these sequences for any reason, you can escape them using {% raw %} and {% endraw %} tags.
Keep in mind that the standard Jinja documentation primarily covers Python syntax and features, whereas Rspamd with Lupa introduces the usage of Lua syntax and features. For detailed information, refer to the Lupa documentation.