Configuration Reference
Hammerhead uses YAML v1.2.2 for configuration. While not the prettiest option for configuration, other languages have been tried before and found to be even wors, so you’ll live (and likely also already know the syntax anyway).
The default configuration is generated at ./config.yaml (i.e. in the directory hammerhead is executed in).
The default configuration does not contain all possible values, but will contain all required values with at least
placeholder value.
This reference will list every config option available, with a description, and an example.
Required keys:
database
database (mapping, required): The configuration for the PostgreSQL database connection.
Examples:
database:
url: postgresql://user:password@hostname:port/dbname?sslmode=disable
database:
url: postgresql://user:password@hostname:port/dbname?sslmode=disable
max_idle_connections: 2
max_idle_lifetime: 5m
max_open_connections: 5
max_open_lifetime: 5m
database.url
url (string, required): The URI to connect to.
This string SHOULD be prefixed with postgresql://, but postgres:// will work for compatibility reasons.
This connection string is passed directly to the database driver, so you can configure other connection-related settings
in this URL (using libpq style query args -
see https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS for more info).
Example:
database:
url: postgresql://user:password@hostname:port/dbname?sslmode=disable
database.max_idle_connections
database.max_idle_connections (integer, optional): The maximum number of idle (not actively running a query)
connections to keep open in the connection pool.
See: max_open_connections
database.max_open_connections
database.max_open_connections (integer, optional): The maximum number of active (running a query) connections the
connection pool is allowed to have.
These options configure the maximum number of parallel connections available to Hammerhead. Generally, you shouldn’t need too many (2+2 may be a good starting point), and you should also be conscious of the additional resource usage incurred by having more postgres connections on the postgres server. More connections will allow for more concurrent operations, but you should only really be concerned about that if your server is exceptionally high traffic and you’re seeing lots of warnings about transactions taking a long time.
By default, there is no connection pooling - this is expected to change.
Examples:
database:
max_idle_connections: 2
database:
max_open_connections: 2
database:
max_idle_connections: 2
max_open_connections: 2
database.max_idle_lifetime
database.max_idle_connections (string (duration), optional): The maximum lifetime of an idle connection.
See: max_open_lifetime
database.max_open_lifetime
database.max_open_connections (string (duration), optional): The maximum lifetime of an active connection.
Controls how long connections live for before being destroyed. You can usually leave this disabled if you aren’t running a fancy postgres server configuration, but if you are, you probably know what these values should be anyway.
Example:
database:
max_idle_lifetime: 5m
database:
max_open_lifetime: 5m
database:
max_idle_lifetime: 5m
max_open_lifetime: 5m
debug
debug (boolean, optional): Enable or disable debug mode.
While you can still get debug logs and whatnot with this option disabled, setting debug: true will enable additional
runtime checks that may affect how the server operates. It is designed to be used with a step-through debugger in mind,
so sometimes some conditions that would usually be handled by logging an error will instead cause actual panics and
potentially crashes. An example of a side effect of enabling this option is that request handlers that don’t write a
response body will cause a crash - with debug disabled, this will log an error instead.
You usually only want to enable this if you are actively debugging Hammerhead.
Example:
debug: true
caches
caches (mapping, optional): Controls the sizes and lifetimes of some runtime caches.
Each cache map has two keys, max_entries, and max_ttl. max_entries (integer, optional) controls how many entries
can be in the cache before old ones start being evicted. By default, it is 4096 x CPU_CORE_COUNT. Set this to zero
to disable limiting the size of caches (not recommended).
max_ttl controls how long entries are allowed to remain in the cache before they are evicted. Set to zero to disable
TTL eviction.
Warning
TTL-based cache evictions are checked on each cache operation (both read and write), which means they are inherently more computationally expensive than simple size-based limits.
On the other hand, size-based eviction is only evaluated on write operation, making them generally cheaper, but may result in Hammerhead holding on to memory purely for “stale” cache entries.
It is recommended you leave caches as their default values unless you are encountering memory constraint issues.
Examples:
caches:
events:
max_entries: 8192
max_ttl: 5m
caches.events
events (mapping, optional): Controls the event cache.
The event cache is a key-value map of {event_id: event_data}. Each value may be up to 64KiB.
Generally you want quite a large event cache, and this is the first thing that will be hit during operations that
involve events (so, most of them), for example: state resolution, fetching events, client sync loops, message
pagination. Setting a lower value will free up memory, but will result in having to run to the database more often to
fetch events.
See caches for more details.
Example:
caches:
events:
max_entries: 8192
listeners
listeners (sequence mapping, required): Configures the addresses that Hammerhead will listen to.
Currently, only TCP socket listeners are supported - unix socket listeners are planned. You must specify at least one listener, but can have as many as you like.
Each listener specified has three keys: host, port, and tls:
host: The address to listen on. usually127.0.0.1and::1for localhost, or0.0.0.0and::for all addresses.port: The port to listen on. Must be between 1 and 65535 inclusive.tls(optional): Iftrue, this listener will use the TLS configuration.
Note
Native TLS is primarily only included for running the test suite. TLS should normally be terminated by your reverse proxy, unless you have an advanced use case.
Tip
All routes (client-to-server, appservices, key-server, server-to-server) are handled by all listeners. If you are used to the Synapse style of having to define which listeners handle which routes, you need not do that here.
127.0.0.1:8008and127.0.0.2:8448both run through the same router, for example.
Example:
listeners:
- host: 0.0.0.0
port: 8008
- host: "::"
port: 8008
- host: 0.0.0.0
port: 8448
tls: true
- host: "::"
port: 8448
tls: true
dont_expose_metrics
dont_expose_metrics (boolean, optional): If true, don’t expose /metrics.
Disables the prometheus metrics exporter route.
Example:
dont_expose_metrics: true
logging
logging (mapping, optional): The configuration for zerolog using zeroconfig.
See zeroconfig for the full schema.
If there are no loggers configured, a coloured “pretty” stdout logger will be configured for you. If you are in debug mode (or Hammerhead was built with a dirty working tree), an additional trace-level JSON logger will be configured for you too.
Example:
logging:
writers:
# - type: journald # uncomment if you're using journald.
- type: stdout
format: pretty-colored
min_level: info
- type: file
format: json
min_level: debug
filename: hammerhead.log # JSON-line file
max_size: 100
max_age: 30
max_backups: 3
compress: true
max_request_bytes
max_request_bytes (integer, optional): The maximum size of a request (in bytes) to read before aborting.
Defaults to 100MiB (104857600).
Since request bodies are buffered into memory (including media) before they’re worked on, it is generally necessary to limit the size of request bodies that will be read. If a request sends a body larger than this, it will only be partially read, and then rejected when the server realises it’s too large (at least one byte over the limit). As a result, this is typically used to limit the size of uploaded media, but that will likely become its own option in the media repository configuration later on.
Caution
Setting this value too high will either result in the OOM reaper coming knocking, and terminating the server process, or potentially undefined behaviour ranging from catchable alloc failures, to critical panics.
Examples:
max_request_bytes: 26214400 # 25MiB
max_request_bytes: 52428800 # 50MiB
max_request_bytes: 104857600 # 100MiB (higher values are typically excessive and unsafe)
max_request_bytes: 536870912 # 512MiB
max_request_bytes: 1073741824 # 1GiB
media_repo
media_repo (mapping, required): The configuration for the media repository.
Hammerhead’s media repository is quite a complex component that is incredibly flexible, so there are a number of configuration options to play with. Fear not, only a couple are necessary.
media_repo.root_path
root_path (string, required): The root path to where media should be stored.
This can either be a fully qualified absolute path, or a relative path, or even point at a symlink.
As long as the subdirectories local, remote, and external can be created at that location.
If the root_path does not exist, it will be created with 750 file permissions (rwxr-x---).
Example:
media_repo:
root_path: /mnt/media/hammerhead
media_repo.temp_path
temp_path (string, required): The path to where temporary media files should be stored.
This can either be a fully qualified absolute path, or a relative path, or even point at a symlink.
Temporary directories starting with the prefix hammerhead_media_ must be creatable by the server.
If the temp_path does not exist, it will be created with 750 file permissions (rwxr-x---).
“temporary media files” are typically files that are being actively uploaded (i.e. before they’re properly saved), and thumbnails that are being worked on. It is unlikely that files will remain in this directory for more than a few seconds at a time.
It is safe to put the temporary directory on an ephemeral file system.
Example:
media_repo:
temp_path: /mnt/media/hammerhead
media_repo.max_size_bytes
max_size_bytes (unsigned 64-bit integer, optional): The maximum size (in bytes) of a single media item. Defaults
to 50MiB (52428800).
Controls the maximum size of file uploads. Attempts to upload media files that are larger than this value will be
rejected, even if the uploader is an administrator.
The server will attempt to reject large uploads if their advertised Content-Length exceeds this value, but in cases
where the Content-Length header is unavailable, the server will read up to max_size_bytes+1 bytes to determine
whether the file is too large.
Important
The value of
max_size_bytesMUST be less than or equal tomax_request_bytes. Setting a value higher thanmax_request_byteswould cause the router component to reject the request for being too large before it could be passed to the media repository component for validation.The server will refuse to start if this condition is not met.
Examples:
media_repo:
max_size_bytes: 8388608 # 8MiB
media_repo:
max_size_bytes: 26214400 # 25MiB
media_repo:
max_size_bytes: 52428800 # 50MiB
media_repo:
max_size_bytes: 104857600 # 100MiB
media_repo:
max_size_bytes: 536870912 # 512MiB
media_repo:
max_size_bytes: 1073741824 # 1GiB
media_repo.security
security (mapping, optional): Configures the security-related settings for the media repository.
Because the media repository is a complex component that exclusively handles potentially untrusted user input, there are several security configurations available. The configuration for this is structured in such a way that the default values are typically sufficient for most people.
media_repo.security.disable_remote_media
disable_remote_media (boolean, optional): If enabled, disables external/remote media functionality.
Defaults to false.
When remote media is disabled, federated media will not be fetched, federated requests for media will be rejected, and server-side URL previews will be disabled.
Example:
media_repo:
security:
disable_remote_media: true
media_repo.security.disallow_mime_types
disallow_mime_types (sequence of strings, optional): Prevents files matching any of the given glob patterns from being
uploaded to the media repository.
When a user attempts to upload a file, if the claimed Content-Type matches any of the given glob patterns, it will be
rejected, even if they are an administrator.
Warning
The content type of encrypted files is
application/octet-stream. Using a glob pattern that blocks this will effectively prevent users from uploading encrypted files.Furthermore, Hammerhead does not currently support MIME sniffing, so malicious users can work around this restriction by lying about or omitting the relevant header.
Example:
media_repo:
security:
disallow_mime_types:
- image/* # ban all images
- application/vnd.microsoft.portable-executable # ban EXE files
- application/zip
- application/x-zip-compressed
- application/gzip
- application/zstd # ban compressed types
media_repo.security.only_admins
only_admins (boolean, optional): If true, only server administrators can upload media.
When enabled, regular users are unable to upload media. This can be used to restrict media uploads to only trusted users.
Example:
media_repo:
security:
only_admins: true
media_repo.security.disable_checksums
disable_checksums (boolean, optional): If true, disable checksum generation and comparison.
Hammerhead makes use of SHA256 checksums to verify the integrity of media when utilising it. Typically, this means a SHA256 checksum is generated when the file has finished uploaded, and is then verified before it is transmitted to requesting clients. This prevents the file being tampered with on disk (although this is easily circumvented by just modifying the hash in the database). Over federation, Hammerhead will include this SHA256 hash in the metadata part of the download, before sending the media content itself. This means other Hammerhead servers that download media from this server will be able to verify the integrity of the downloaded file before processing it. This is not a Matrix behaviour and is currently exclusive to Hammerhead.
Turning off checksumming may improve performance as it avoids an extra disk roundtrip, however this opens up the potential for corrupted or tampered files to be served.
Files that fail checksum validation are not immediately deleted, however will cause an error.
Example:
media_repo:
security:
disable_checksums: true # not recommended
media_repo.security.minimum_account_age
minimum_account_age (string (duration), optional): The minimum age an account must be before it can upload files.
Restricts uploading media to accounts that have existed for longer than the given duration, excluding administrators.
Example:
media_repo:
security:
minimum_account_age: 5m # 5 minutes
media_repo.security.disable_server_side_thumbnails
disable_server_side_thumbnails (boolean, optional): Disables server-side thumbnail generation.
Disabling server-side thumbnails may be desirable to reduce the amount of processing done on user-generated content, which is a large attack surface. The downside of this is that thumbnails will generally be unavailable for uploaded media, such as user avatars, resulting in increased bandwidth and unhappy impatient users.
Example:
media_repo:
security:
disallow_server_side_thumbnails: true
media_repo.security.acl
acl (mapping, optional): An ACL event body that defines which servers are and aren’t allowed to
communicate media.
Sets an access-control-list in the same way as room ACLs - servers in the allow are always allowed, unless they are
denied in the deny list. You cannot create an ACL that bans the local server.
The ACL is bidirectional - forbidden servers won’t be able to download media from you, but you also won’t be able to download media from them.
Examples:
# Explicit denylist
media_repo:
security:
acl:
allow: ["*"] # Allow all servers
deny:
- evil.matrix.example # Don't allow media communication with evil.matrix.example specifically.
- "*.bad.matrix.example" # Don't allow media communication with any server name under "bad.matrix.example".
# Explicit denylist
media_repo:
security:
acl:
allow:
- "SERVER_NAME_HERE" # Your server name has to be explicitly listed
- "good.matrix.example" # Allow media communication with good.matrix.example
# No need for an explicit `deny` here.
media_repo.security.enable_streaming
enable_streaming (boolean, optional): Allow streaming media over federation.
When enabled, media can be streamed directly to the requesting client before the server has finished downloading it over federation. This is incompatible with checksum verification, which will instead be ignored in this case. The benefit of this feature is that users can start streaming files from remote servers almost immediately, rather than having to wait for the homeserver to finish downloading it before uploading it again, which is particularly useful for videos. However, the lack of checksum verification, or preprocessing as a whole, means that other security protections may not be effective, and potentially invalid or illegal data may be sent to the client unknowingly.
You should evaluate how this fits into your threat model before changing this value.
Example:
media_repo:
security:
enable_streaming: true
old_verify_keys
old_verify_keys (mapping, optional): A mapping of previous signing key IDs to when they expired.
A map of old signature keys that can be used to verify events. You should prefer to import the keys via the command
hammerhead -import-signing-key, but if you do not have the private key anymore you can advertise it here instead.
The keys of the map are the key IDs (e.g. ed25519:foo), and the value has two required keys:
key: The full public signing key of this key.- expired_ts: The unix timestamp (milliseconds) when this key expired
Example:
old_verify_keys:
- ed25519:auto:
key: Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw
expired_ts: 1576767829750
default_room_version
default_room_version (string, optional): Defines the default room version for new rooms.
While clients can specify the room version they want to create when calling /createRoom, if they do not, the
room version specified here will be used instead.
Note
You probably don’t need to set this - the latest version that Hammerhead fully supports is used by default, meaning generally you should just update your server if the default version is not new enough. Overriding the default value may have unintended consequences.
Example:
default_room_version: 12
registration
registration (mapping, optional): The registration settings for this server.
Controls the registration requirements for the server. If omitted, registration is disabled.
Example:
registration:
enabled: true
token: ed03d0b58fa20618be08fe20c1eb05a0
password_requirements:
min_entropy: 70
registration.enabled
enabled (boolean, optional): Whether registration is enabled at all. Defaults to false.
If registration is disabled, no new accounts can be created without the admin API, even if requirements like a token are set.
Example:
registration:
enabled: true
registration.i_have_a_very_good_reason_or_i_am_stupid_and_want_to_allow_unsafe_open_registration
i_have_a_very_good_reason_or_i_am_stupid_and_want_to_allow_unsafe_open_registration (boolean, optional):
If set to true, registration will be unsafely open.
Enables registration without any registration requirements. This is dangerous, as this means your only defense against automated bots mass-registering on your server is ratelimits, and you have no way to prevent untrusted users registering and potentially being abusive. You should never need to enable this!
Example:
registration:
i_have_a_very_good_reason_or_i_am_stupid_and_want_to_allow_unsafe_open_registration: false
registration.token
token (string, optional): The pre-shared secret to challenge registrations with.
A pre-shared token that is required as a second step to register an account. This allows you to give out an “invite code” to people you trust, so that they can create accounts themselves. This is the recommended way to have registration enabled.
If omitted or empty, the registration token will be disabled.
Example:
registration:
token: ed03d0b58fa20618be08fe20c1eb05a0
registration.password_requirements
password_requirements (mapping, optional): Controls the requirements for passwords on this server.
Allows you to set minimum password length and entropy requirements. Not applied to accounts created via the admin API.
Example:
registration:
password_requirements:
min_entropy: 50 # require at least 50 bits of entropy
min_length: 0 # disable length requirements
room_directory.admin_only
admin_only (boolean, optional): If enabled, only server admins are able to publish to the room directory.
When enabled, only admin users can publish rooms to the public room directory (i.e. room list). Note that when enabled, users can still create and use aliases, they just cannot publish them.
Example:
room_directory:
admin_only: true
server_name
server_name (string, required): The name of this server.
This is not necessarily your domain name - it is the part of the ID that appears at the end of user IDs, and room
aliases. For example, @user:matrix.example would have the server name matrix.example, even if traffic was
ultimately served from hammerhead.matrix.example.
The server name can be an IP address (not recommended) or DNS name, optionally with a port. Typically, you will use a DNS name without a port here (you configure the port later).
Caution
You cannot change the server name after registering the first user.
Examples:
server_name: matrix.example
server_name: matrix.example:8448 # not recommended
tls
tls (mapping, optional): Configures TLS options for TLS listeners.
Configures the certificate file and key file for serving TLS directly from listeners. You can generate a self-signed certificate with
openssl req -newkey rsa:4096 -nodes -keyout key.pem -x509 -days 365 -out cert.pem
Example:
tls:
cert_file: path/to/cert.pem
key_file: path/to/key.pem
well_known
well_known (mapping, optional): Controls the values returned to the well-known helper routes.
well_known.client
client (string, optional): The base URL for client-to-server interactions.
Example:
well_known:
client: https://client.matrix.example