<a id="install"></a>

# Configuration instructions

## Installing Weblate

Depending on your setup and experience, choose an appropriate installation method for you:

* [Installing using Docker](https://docs.weblate.org/no/latest/admin/install/docker.md), recommended for production setups.
* Virtualenv installation, recommended for production setups:
  * [Installing on Debian and Ubuntu](https://docs.weblate.org/no/latest/admin/install/venv-debian.md)
  * [Installing on SUSE and openSUSE](https://docs.weblate.org/no/latest/admin/install/venv-suse.md)
  * [Installing on RedHat, Fedora and CentOS](https://docs.weblate.org/no/latest/admin/install/venv-redhat.md)
  * [Installing on macOS](https://docs.weblate.org/no/latest/admin/install/venv-macos.md)
* [Installing from sources](https://docs.weblate.org/no/latest/admin/install/source.md), recommended for development.
* [Installing on OpenShift](https://docs.weblate.org/no/latest/admin/install/openshift.md)
* [Installing on Kubernetes](https://docs.weblate.org/no/latest/admin/install/kubernetes.md)

<a id="architecture"></a>

## Architecture overview

Web server
: Handling incoming HTTP requests, [Serving static files](#static-files).

Celery workers
: [Background tasks using Celery](#celery) are executed here.
  <br/>
  Depending on your workload, you might want to customize the number of workers.
  <br/>
  Use dedicated node when scaling Weblate horizontally.

Application server
: A WSGI or ASGI server serving web pages to users.
  <br/>
  Use dedicated node when scaling Weblate horizontally.

Database
: PostgreSQL database server for storing all the content, see [Database setup for Weblate](#database-setup).
  <br/>
  Use dedicated database node for sites with hundreds of millions of hosted words.

Datastore
: Key/value datastore such as Valkey or Redis server for cache and tasks queue, see [Background tasks using Celery](#celery).
  <br/>
  Use dedicated node when scaling Weblate horizontally.

File system
: File system storage for storing VCS repositories and uploaded user data. This is shared by all the processes.
  <br/>
  Use networked storage when scaling Weblate horizontally.

E-mail server
: SMTP server for outgoing e-mail, see [Configuring outgoing e-mail](#out-mail). It can be provided externally.

#### HINT
[Installing using Docker](https://docs.weblate.org/no/latest/admin/install/docker.md) includes PostgreSQL and Valkey, making the installation easier.

<a id="requirements"></a>

## Software requirements

### Operating system

Weblate is known to work on Linux, FreeBSD and macOS. Other Unix like systems
will most likely work too.

Weblate is not supported on Windows. But it may still work and patches are
happily accepted.

#### SEE ALSO
[Architecture overview](#architecture) describes overall Weblate architecture and required services.

<a id="python-deps"></a>

### Python dependencies

Weblate is written in [Python](https://www.python.org/) and supports Python
3.12 or newer. You can install dependencies using pip or from your
distribution packages, full list is available in `requirements.txt`.

Most notable dependencies:

Django
: [https://www.djangoproject.com/](https://www.djangoproject.com/)

Celery
: [https://docs.celeryq.dev/](https://docs.celeryq.dev/)

Translate Toolkit
: [https://toolkit.translatehouse.org/](https://toolkit.translatehouse.org/)

translation-finder
: [https://github.com/WeblateOrg/translation-finder](https://github.com/WeblateOrg/translation-finder)

Python Social Auth
: [https://python-social-auth.readthedocs.io/](https://python-social-auth.readthedocs.io/)

Django REST Framework
: [https://www.django-rest-framework.org/](https://www.django-rest-framework.org/)

<!-- Table is generated using scripts/show-extras.py -->

#### Optional dependencies

| Optional dependency specifier   | Python packages                                                                                                                                                           | Weblate feature                                                                                                                   |
|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `amazon`                        | [boto3](https://pypi.org/project/boto3/)<br/><br/><br/>[django-ses](https://pypi.org/project/django-ses/)<br/><br/>                                                       | [Amazon Translate](https://docs.weblate.org/no/latest/admin/machine.md#mt-aws), AWS SES e-mail backend                                    |
| `asgi`                          | [granian](https://pypi.org/project/granian/)<br/><br/>                                                                                                                    | ASGI server for Weblate                                                                                                           |
| `gelf`                          | [logging-gelf](https://pypi.org/project/logging-gelf/)<br/><br/>                                                                                                          | [Graylog log management](#graylog)                                                             |
| `gerrit`                        | [git-review](https://pypi.org/project/git-review/)<br/><br/>                                                                                                              | [Gerrit review requests](https://docs.weblate.org/no/latest/admin/code-hosting.md#code-hosting-gerrit)                                         |
| `google`                        | [google-cloud-storage](https://pypi.org/project/google-cloud-storage/)<br/><br/><br/>[google-cloud-translate](https://pypi.org/project/google-cloud-translate/)<br/><br/> | [Google Cloud Translation Advanced](https://docs.weblate.org/no/latest/admin/machine.md#mt-google-translate-api-v3) with glossary support |
| `google-errors`                 | [google-cloud-error-reporting](https://pypi.org/project/google-cloud-error-reporting/)<br/><br/>                                                                          | [Collecting error reports and monitoring performance](#collecting-errors)                                |
| `ldap`                          | [django-auth-ldap](https://pypi.org/project/django-auth-ldap/)<br/><br/>                                                                                                  | [LDAP authentication](https://docs.weblate.org/no/latest/admin/auth.md#ldap-auth)                                                      |
| `mercurial`                     | [mercurial](https://pypi.org/project/mercurial/)<br/><br/>                                                                                                                | [Mercurial](https://docs.weblate.org/no/latest/vcs.md#vcs-mercurial)                                                            |
| `postgres`                      | [psycopg](https://pypi.org/project/psycopg/)<br/><br/>                                                                                                                    | PostgreSQL, see [Database setup for Weblate](#database-setup)                                         |
| `rollbar`                       | [rollbar](https://pypi.org/project/rollbar/)<br/><br/>                                                                                                                    | [Collecting error reports and monitoring performance](#collecting-errors)                                |
| `saml`                          | [python3-saml](https://pypi.org/project/python3-saml/)<br/><br/><br/>[xmlsec](https://pypi.org/project/xmlsec/)<br/><br/>                                                 | [SAML authentication](https://docs.weblate.org/no/latest/admin/auth.md#saml-auth)                                                      |
| `saml2idp`                      | [djangosaml2idp2](https://pypi.org/project/djangosaml2idp2/)<br/><br/>                                                                                                    | Integrating SAML 2 IDP into Weblate                                                                                               |
| `sphinx`                        | [Sphinx](https://pypi.org/project/Sphinx/)<br/><br/>                                                                                                                      | Needed for [Update POT file (Sphinx)](https://docs.weblate.org/no/latest/admin/addons.md#addon-weblate-gettext-sphinx)                   |
| `wllegal`                       | [wllegal](https://pypi.org/project/wllegal/)<br/><br/>                                                                                                                    | Hosted Weblate integration                                                                                                        |
| `wsgi`                          | [granian](https://pypi.org/project/granian/)<br/><br/>                                                                                                                    | WSGI server for Weblate                                                                                                           |
| `zxcvbn`                        | [django-zxcvbn-password-validator](https://pypi.org/project/django-zxcvbn-password-validator/)<br/><br/>                                                                  | [Password authentication](https://docs.weblate.org/no/latest/admin/auth.md#password-authentication)                                    |

When installing using pip, you can directly specify desired features when installing:

```sh
uv pip install "weblate[Postgres,Amazon,SAML]"
```

Or you can install Weblate with all optional features:

```sh
uv pip install "weblate[all]"
```

Or you can install Weblate without any optional features:

```sh
uv pip install weblate
```

<a id="troubleshoot-pip-install"></a>

### Troubleshooting pip install

`ffi_prep_closure(): bad user_data (it seems that the version of the libffi library seen at runtime is different from the 'ffi.h' file seen at compile-time)`
: This is caused by incompatibility of binary packages distributed via PyPI
  with the distribution. To address this, you need to rebuild the package
  on your system:
  <br/>
  ```sh
  uv pip install --force-reinstall --no-binary :all: cffi
  ```

`error: ‘xmlSecKeyDataFormatEngine’ undeclared (first use in this function); did you mean ‘xmlSecKeyDataFormat’?`
: This is a known issue of the xmlsec package, please see [https://github.com/xmlsec/python-xmlsec/issues/314](https://github.com/xmlsec/python-xmlsec/issues/314).

`lxml & xmlsec libxml2 library version mismatch`
: The `lxml` and `xmlsec` packages have to be built against one `libxml2`. You should build them locally to avoid this issue:
  <br/>
  ```sh
  uv pip install --force-reinstall --no-binary xmlsec --no-binary lxml lxml xmlsec
  ```

### Other system requirements

The following dependencies have to be installed on the system:

`Git`
: [https://git-scm.com/](https://git-scm.com/)

`git-review` (optional for Gerrit support)
: [git-review](https://pypi.org/project/git-review/)

`git-svn` (optional for Subversion support)
: [https://git-scm.com/docs/git-svn](https://git-scm.com/docs/git-svn)

`tesseract` (needed only if **tesserocr** binary wheels are not available for your system)
: [https://github.com/tesseract-ocr/tesseract](https://github.com/tesseract-ocr/tesseract)

### Build-time dependencies

To build some of the [Python dependencies](#python-deps) you might need to install their
dependencies. This depends on how you install them, so please consult
individual packages for documentation. You won’t need those if using prebuilt
`Wheels` while installing using `pip` or when you use distribution packages.

<a id="hardware"></a>

## Hardware requirements

Weblate should run on any contemporary hardware without problems, the following is
the minimal configuration required to run Weblate on a single host (Weblate, database
and web server):

* 3 GB of RAM
* 2 CPU cores
* 1 GB of storage space

#### NOTE
Actual requirements for your installation of Weblate vary heavily based on the size of
the translations managed in it.

### Memory usage

The more memory the better - it is used for caching on all
levels (file system, database and Weblate).
For hundreds of translation components, at least 4 GB of RAM is
recommended.

#### HINT
For systems with less memory than recommended, [Single-process Celery setup](#minimal-celery) is recommended.

### CPU usage

Many concurrent users increase the amount of needed CPU cores.

Weblate 2026.8 introduced NumPy as a required dependency. On x86-64 systems,
the optimized NumPy build bundled in the Docker image requires an x86-64-v2
compatible CPU. Without the required CPU features, NumPy fails to load and
Weblate cannot start.

Before upgrading, check for the required SSE4.2 CPU feature on the Linux system
running Docker:

```sh
grep sse4_2 /proc/cpuinfo
```

Empty output indicates that a required CPU feature is unavailable. This is a
preliminary check; finding SSE4.2 does not verify all x86-64-v2 CPU features.

If Docker runs in a virtual machine, run the check inside the guest. Virtual
machines can hide CPU features supported by the host. Configure the virtual
machine to expose the required host CPU features, then reboot the guest. If
the physical CPU lacks the required features, upgrade the hardware.

### Storage usage

The typical database storage usage is around 300 MB per 1 million hosted words.

Storage space needed for cloned repositories varies, but Weblate tries to keep
their size minimal by doing shallow clones.

### Storage performance

Version control operations perform many filesystem metadata lookups. The
`vcs` subdirectory in [`DATA_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-DATA_DIR) therefore needs low read
latency; storage with slow metadata access can make operations such as
**git status** take a long time even when its bulk throughput is good.
Keep [`CACHE_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CACHE_DIR) on low-latency local or temporary storage when
possible.

The deployment checks measure metadata lookup latency for both locations and
warn when the median latency exceeds 10 milliseconds. This is an approximate
point-in-time measurement affected by filesystem and system load. Rerun
**weblate check --deploy** before changing the storage configuration.

### Nodes

For small and medium-sized sites (millions of hosted words), all Weblate components (see
[Architecture overview](#architecture)) can be run on a single node.

When you grow to hundreds of millions of hosted words, it is recommended to
have a dedicated node for database (see [Database setup for Weblate](#database-setup)).

## Verifying release artifacts

Release archives can be verified using the signatures, attestations, and SBOMs
published with GitHub release assets. See [Verifying release artifacts](https://docs.weblate.org/no/latest/security/release-artifacts.md#verify).

<a id="file-permissions"></a>

## Filesystem permissions

The Weblate process needs to be able to read and write to the directory where
it keeps data - [`DATA_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-DATA_DIR). All files within this directory should be
owned and writable by the user running all Weblate processes (typically WSGI and Celery, see [Running server](#server) and [Background tasks using Celery](#celery)).

The default configuration places them in the same tree as the Weblate sources, however
you might prefer to move these to a better location such as:
`/var/lib/weblate`.

Weblate tries to create these directories automatically, but it will fail
when it does not have permissions to do so.

The configured [`CACHE_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CACHE_DIR) also has to be writable by the Weblate
process and has to allow executing generated helper files. Do not mount
[`CACHE_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CACHE_DIR) with the `noexec` option.

You should also take care when running [Management commands](https://docs.weblate.org/no/latest/admin/management.md#manage), as they should be ran
under the same user as Weblate itself is running, otherwise permissions on some
files might be wrong.

In the Docker container, all files in the `/app/data` volume have to be
owned by the `weblate` user inside the container (UID 1000).

#### SEE ALSO
[Serving static files](#static-files)

<a id="database-setup"></a>

## Database setup for Weblate

It is recommended to run Weblate with a PostgreSQL database server.

PostgreSQL 13 and higher is supported. PostgreSQL 15 or newer is recommended.

#### SEE ALSO
* [Use a powerful database engine](#production-database)
* [Databases](https://docs.djangoproject.com/en/stable/ref/databases/)
* [Migrating from other databases to PostgreSQL](https://docs.weblate.org/no/latest/admin/upgrade.md#database-migration)

<a id="db-connections"></a>

### Database connections

In the default configuration, each Weblate process keeps a persistent
connection to the database. Persistent connections improve Weblate
responsiveness, but might require more resources for the database server.
Please consult [`CONN_MAX_AGE`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-CONN_MAX_AGE) and
[Persistent connections](https://docs.djangoproject.com/en/stable/ref/databases/#persistent-database-connections) for more info.

Weblate needs at least the following number of connections:

* $(4 \times \mathit{nCPUs}) + 2$ for Celery processes
* $\mathit{nCPUs} + 1$ for WSGI workers

This applies to Docker container defaults and example configurations provided
in this documentation, but the numbers will change once you customize the amount of
WSGI workers or adjust parallelism of Celery.

The actual limit for the number of database connections needs to be higher to
account for the following situations:

* [Management commands](https://docs.weblate.org/no/latest/admin/management.md#manage) need their connection as well.
* If a process is killed (for example by OOM killer), it might block the existing connection until timeout.

#### SEE ALSO
[Background tasks using Celery](#celery),
[Sample configuration for NGINX and uWSGI](#uwsgi),
[`WEBLATE_WORKERS`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_WORKERS)

<a id="postgresql"></a>

### PostgreSQL

PostgreSQL is usually the best choice for Django-based sites. It’s the reference
database used for implementing Django database layer.

#### NOTE
Weblate uses trigram extension which has to be installed separately in some
cases. Look for `postgresql-contrib` or a similarly named package.

#### SEE ALSO
[PostgreSQL notes](https://docs.djangoproject.com/en/stable/ref/databases/#postgresql-notes)

<a id="dbsetup-postgres"></a>

#### Creating a database in PostgreSQL

It is usually a good idea to run Weblate in a separate database, and separate user account:

```sh
# If PostgreSQL was not installed before, set the main password
sudo -u postgres psql postgres -c "\password postgres"

# Create a database user called "weblate"
sudo -u postgres createuser --superuser --pwprompt weblate

# Create the database "weblate" owned by "weblate"
sudo -u postgres createdb -E UTF8 -O weblate weblate
```

#### HINT
If you don’t want to make the Weblate user a superuser in PostgreSQL, you can
omit that. In that case you will have to perform some of the migration steps
manually as a PostgreSQL superuser in schema Weblate will use:

```postgres
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS btree_gin;
CREATE EXTENSION IF NOT EXISTS btree_gist;
```

<a id="config-postgresql"></a>

#### Configuring Weblate to use PostgreSQL

The `settings.py` snippet for PostgreSQL:

```python
DATABASES = {
    "default": {
        # Database engine
        "ENGINE": "django.db.backends.postgresql",
        # Database name
        "NAME": "weblate",
        # Database user
        "USER": "weblate",
        # Configures name of the PostgreSQL role to alter during the database migration
        # "ALTER_ROLE": "weblate",
        # Database password
        "PASSWORD": "password",
        # Set to empty string for localhost
        "HOST": "database.example.com",
        # Set to empty string for default
        "PORT": "",
        # Persistent connections
        "CONN_MAX_AGE": None,
        "CONN_HEALTH_CHECKS": True,
    }
}
```

The database migration performs [ALTER ROLE](https://www.postgresql.org/docs/16/sql-alterrole.html) on the database role used
by Weblate. In most cases, the name of the role matches the username. In more
complex setups the role name is different from the username, and you will get an error
about non-existing role during the database migration
(`psycopg2.errors.UndefinedObject: role "weblate@hostname" does not exist`).
This is known to happen with Azure Database for PostgreSQL, but it’s not
limited to this environment. Please set `ALTER_ROLE` to change the name of the
role Weblate should alter during the database migration.

#### SEE ALSO
[Database connections](#db-connections)

## Other configurations

<a id="out-mail"></a>

### Configuring outgoing e-mail

Weblate sends out e-mails on various occasions - for account activation and on
various notifications configured by users. For this it needs access to an SMTP
server.

The mail server setup is configured using these settings:
[`EMAIL_HOST`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_HOST), [`EMAIL_HOST_PASSWORD`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_HOST_PASSWORD),
[`EMAIL_USE_TLS`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_USE_TLS), [`EMAIL_USE_SSL`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_USE_SSL),
[`EMAIL_HOST_USER`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_HOST_USER) and [`EMAIL_PORT`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_PORT). Their
names are quite self-explanatory, but you can find more info in the
Django documentation.

#### HINT
In case you get error about not supported authentication (for example
`SMTP AUTH extension not supported by server`), it is most likely caused
by using insecure connection and server refuses to authenticate this way.
Try enabling [`EMAIL_USE_TLS`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_USE_TLS) in such case.

#### SEE ALSO
* [Not receiving e-mails from Weblate](https://docs.weblate.org/no/latest/contributing/debugging.md#debug-mails)
* [Configuring outgoing e-mail in Docker container](https://docs.weblate.org/no/latest/admin/install/docker.md#docker-mail)

<a id="reverse-proxy"></a>

### Running behind reverse proxy

Several features in Weblate rely on correct HTTP headers being passed to
Weblate. When using reverse proxy, please make sure that the needed information
is correctly passed.

To debug this configuration, you can look at HTTP environment in
[Performance report](https://docs.weblate.org/no/latest/admin/admin.md#manage-performance).

Client IP address
: This is needed for [Rate limiting](https://docs.weblate.org/no/latest/admin/optionals.md#rate-limit) or [Activity](https://docs.weblate.org/no/latest/user/profile.md#audit-log).
  <br/>
  Weblate parses IP address from the `REMOTE_ADDR`, which is set by the WSGI
  handler. This might be empty (when using socket for WSGI) or contain a
  reverse proxy address, so Weblate needs an additional HTTP header with
  a client IP address.
  <br/>
  Enabling [`IP_BEHIND_REVERSE_PROXY`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_BEHIND_REVERSE_PROXY) should be sufficient for the most
  usual setups, but you might need to adjust [`IP_PROXY_HEADER`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_PROXY_HEADER) and
  [`IP_PROXY_OFFSET`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_PROXY_OFFSET) as well (use [`WEBLATE_IP_PROXY_HEADER`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_IP_PROXY_HEADER)
  and [`WEBLATE_IP_PROXY_OFFSET`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_IP_PROXY_OFFSET) in the Docker container).
  <br/>
  The reverse proxy which connects to Weblate must overwrite the configured
  header or append a verified peer address at the position selected by
  [`IP_PROXY_OFFSET`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_PROXY_OFFSET). Do not select a client-supplied address, and do
  not expose the application server through a path which bypasses the trusted
  proxy.
  <br/>
  When using `X-Forwarded-For` with the Docker container, configure
  [`WEBLATE_TRUSTED_PROXY_ADDRESSES`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_TRUSTED_PROXY_ADDRESSES) with the reverse proxies allowed
  to supply client addresses.
  <br/>
  #### HINT
  This configuration cannot be turned on by default, because it would allow IP
  address spoofing on installations that don’t have a properly configured
  reverse proxy.

Server host name
: The [Host](https://www.rfc-editor.org/info/rfc7230#section-5.4) header should match to whatever is configured as
  [`SITE_DOMAIN`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SITE_DOMAIN). Additional configuration might be needed in your
  reverse proxy (for example use `ProxyPreserveHost On` for Apache or
  `proxy_set_header Host $host;` with nginx).
  <br/>
  #### HINT
  CSRF verification failed errors are often caused by a mismatch between
  the [Host](https://www.rfc-editor.org/info/rfc7230#section-5.4) header and configured [`SITE_DOMAIN`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SITE_DOMAIN).

Client protocol
: Not passing correct protocol may cause Weblate to end up in redirection
  loop trying to upgrade client to HTTPS. Make sure it is correctly exposed by
  the reverse proxy as *X-Forwarded-Proto*.
  <br/>
  This header then needs to be configured in
  [`SECURE_PROXY_SSL_HEADER`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SECURE_PROXY_SSL_HEADER) (`settings.py`) or
  [`WEBLATE_SECURE_PROXY_SSL_HEADER`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_SECURE_PROXY_SSL_HEADER) (Docker environment).
  <br/>
  #### IMPORTANT
  The header value is case-sensitive in the configuration, so
  `WEBLATE_SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,https` and
  `WEBLATE_SECURE_PROXY_SSL_HEADER=HTTP_X_FORWARDED_PROTO,HTTPS` are not
  interchangeable.
  <br/>
  #### HINT
  If you are getting a «Too many redirects» error from the browser, this is
  most likely caused by mismatch between the actual protocol (HTTPS) and
  what is observed by Weblate.
  <br/>
  #### Versionchanged
  Changed in version 5.13: The protocol proxy headers are automatically handled by
  **gunicorn** in the default configuration, but other WSGI servers
  have more secure configuration and require explicit setting of this.
  <br/>
  Since Weblate 5.13 the Docker container is using **granian** and
  it now requires the explicit configuration of
  [`WEBLATE_SECURE_PROXY_SSL_HEADER`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_SECURE_PROXY_SSL_HEADER).

#### SEE ALSO
* [SSL terminating proxy](https://docs.weblate.org/no/latest/admin/install/docker.md#docker-ssl-proxy)
* [Rate limiting](https://docs.weblate.org/no/latest/admin/optionals.md#rate-limit)
* [Activity](https://docs.weblate.org/no/latest/user/profile.md#audit-log)
* [Sample configuration for NGINX and Granian](#nginx-granian)
* [Sample configuration for NGINX and Gunicorn](#nginx-gunicorn)
* [Sample configuration for NGINX and uWSGI](#uwsgi)
* [Sample configuration for Apache](#apache)
* [Sample configuration for Apache and Gunicorn](#apache-gunicorn)
* [`IP_BEHIND_REVERSE_PROXY`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_BEHIND_REVERSE_PROXY)
* [`IP_PROXY_HEADER`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_PROXY_HEADER)
* [`IP_PROXY_OFFSET`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-IP_PROXY_OFFSET)
* [`SECURE_PROXY_SSL_HEADER`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SECURE_PROXY_SSL_HEADER)
* [`WEBLATE_IP_PROXY_HEADER`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_IP_PROXY_HEADER)
* [`WEBLATE_TRUSTED_PROXY_ADDRESSES`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_TRUSTED_PROXY_ADDRESSES)
* [`WEBLATE_IP_PROXY_OFFSET`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_IP_PROXY_OFFSET)

<a id="http-proxy"></a>

### HTTP proxy

Weblate supports per-protocol HTTP proxy configuration for outbound HTTP
requests and Git repositories. Define the proxy environment variables in
`settings.py`:

```python
import os

os.environ["http_proxy"] = "http://proxy.example.com:8080"
os.environ["https_proxy"] = "http://proxy.example.com:8080"
```

Only `http_proxy` and `https_proxy` are supported. Generic and bypass
variables such as `all_proxy` and `no_proxy`, operating-system proxy
configuration, and VCS-specific proxy configuration are not supported.

#### SEE ALSO
[Proxy environment variables](https://everything.curl.dev/usingcurl/proxies/env.html)

<a id="configuration"></a>

## Adjusting configuration

#### SEE ALSO
[Sample configuration](https://docs.weblate.org/no/latest/admin/sample.md#sample-configuration)

Copy `weblate/settings_example.py` to `weblate/settings.py` and
adjust it to match your setup. You will probably want to adjust the following
options:

<a id="std-setting-ADMINS"></a>

`ADMINS`

> List of site administrators to receive notifications when something goes
> wrong, for example notifications on failed merges, or Django errors.

> Contact form sends e-mail on these as well unless [`ADMINS_CONTACT`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-ADMINS_CONTACT)
> is configured.

> #### SEE ALSO
> * [`ADMINS`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-ADMINS)
> * [`ADMINS_CONTACT`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-ADMINS_CONTACT)
> * [Properly configure admins](#production-admins)

<a id="std-setting-ALLOWED_HOSTS"></a>

`ALLOWED_HOSTS`

> You need to set this to list the hosts your site is supposed to serve. For
> example:

> ```python
> ALLOWED_HOSTS = ["demo.weblate.org"]
> ```

> Alternatively you can include wildcard:

> ```python
> ALLOWED_HOSTS = ["*"]
> ```

> #### SEE ALSO
> * [`ALLOWED_HOSTS`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-ALLOWED_HOSTS)
> * [`WEBLATE_ALLOWED_HOSTS`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_ALLOWED_HOSTS)
> * [Allowed hosts setup](#production-hosts)

<a id="std-setting-SESSION_ENGINE"></a>

`SESSION_ENGINE`

> Configure how your sessions will be stored. In case you keep the default
> database backend engine, you should schedule:
> **weblate clearsessions** to remove stale session data from the
> database.

> If you are using Valkey or Redis as cache (see [Configure cache](#production-cache)) it is
> recommended to use it for sessions as well:

> ```python
> SESSION_ENGINE = "django.contrib.sessions.backends.cache"
> ```

> #### SEE ALSO
> * [Configuring the session engine](https://docs.djangoproject.com/en/stable/topics/http/sessions/#configuring-sessions)
> * [`SESSION_ENGINE`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SESSION_ENGINE)

<a id="std-setting-DATABASES"></a>

`DATABASES`

> Connectivity to database server, please check Django’s documentation for more
> details.

> #### SEE ALSO
> * [Database setup for Weblate](#database-setup)
> * [`DATABASES`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-DATABASES)
> * [Databases](https://docs.djangoproject.com/en/stable/ref/databases/)

<a id="std-setting-DEBUG"></a>

`DEBUG`

> Disable this for any production server. With debug mode enabled, Django will
> show backtraces in case of error to users, when you disable it, errors will
> be sent per e-mail to `ADMINS` (see above).

> Debug mode also slows down Weblate, as Django stores much more info
> internally in this case.

> #### SEE ALSO
> * [`DEBUG`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-DEBUG)
> * [Disable debug mode](#production-debug)

<a id="std-setting-DEFAULT_FROM_EMAIL"></a>

`DEFAULT_FROM_EMAIL`

> E-mail sender address for outgoing e-mail, for example registration e-mails.

> #### SEE ALSO
> [`DEFAULT_FROM_EMAIL`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-DEFAULT_FROM_EMAIL)

<a id="std-setting-SECRET_KEY"></a>

`SECRET_KEY`

> Key used by Django to sign some info in cookies, see
> [Django secret key](#production-secret) for more info.

> #### SEE ALSO
> [`SECRET_KEY`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SECRET_KEY)

<a id="std-setting-SERVER_EMAIL"></a>

`SERVER_EMAIL`

> E-mail used as sender address for sending e-mails to the administrator, for
> example notifications on failed merges.

> #### SEE ALSO
> [`SERVER_EMAIL`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SERVER_EMAIL)

<a id="tables-setup"></a>

## Filling up the database

After your configuration is ready, you can run
[`migrate`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-migrate) to create the database structure. Now you should be
able to create translation projects using the admin interface.

Once you are done, you should also check the Performance report in the
admin interface, which will give you hints of potential non optimal configuration on your
site.

#### SEE ALSO
* [Configuration](https://docs.weblate.org/no/latest/admin/config.md#config)
* [List of privileges](https://docs.weblate.org/no/latest/admin/access.md#privileges)

<a id="production"></a>

## Production setup

For a production setup you should carry out adjustments described in the following sections.
The most critical settings will trigger a warning, which is indicated by an
exclamation mark in the top bar if signed in as a superuser:

![image](screenshots/admin-wrench.webp)

It is also recommended to inspect checks triggered by Django (though you might not
need to fix all of them):

```sh
weblate check --deploy
```

You can also review the very same checklist at [Performance report](https://docs.weblate.org/no/latest/admin/admin.md#manage-performance) in the [Management interface](https://docs.weblate.org/no/latest/admin/admin.md#management-interface).

#### SEE ALSO
[Deployment checklist](https://docs.djangoproject.com/en/stable/howto/deployment/checklist/)

<a id="production-debug"></a>

### Disable debug mode

Disable Django’s debug mode ([`DEBUG`](#std-setting-DEBUG)) by:

```python
DEBUG = False
```

With debug mode on, Django stores all executed queries and shows users backtraces
of errors, which is not desired in a production setup.

#### SEE ALSO
[Adjusting configuration](#configuration)

<a id="production-admins"></a>

### Properly configure admins

Set the correct admin addresses to the [`ADMINS`](#std-setting-ADMINS) setting to define who will receive
e-mails in case something goes wrong on the server, for example:

```python
ADMINS = ("Your Name <your_email@example.com>",)
```

#### SEE ALSO
[Adjusting configuration](#configuration)

<a id="production-site"></a>

### Set correct site domain

Adjust site name and domain in the admin interface, otherwise links in RSS or
registration e-mails will not work. This is configured using
[`SITE_DOMAIN`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SITE_DOMAIN) which should contain site domain name.

#### Versionchanged
Changed in version 4.2: Prior to the 4.2 release the Django sites framework was used instead, please
see [The “sites” framework](https://docs.djangoproject.com/en/stable/ref/contrib/sites/).

#### SEE ALSO
* [Allowed hosts setup](#production-hosts)
* [Correctly configure HTTPS](#production-ssl)
* [`SITE_DOMAIN`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SITE_DOMAIN)
* [`WEBLATE_SITE_DOMAIN`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_SITE_DOMAIN)
* [`ENABLE_HTTPS`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-ENABLE_HTTPS)

<a id="production-ssl"></a>

### Correctly configure HTTPS

It is strongly recommended to run Weblate using the encrypted HTTPS protocol.
After enabling it, you should set [`ENABLE_HTTPS`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-ENABLE_HTTPS) in the settings:

```python
ENABLE_HTTPS = True
```

#### HINT
You might want to set up HSTS as well, see
[SSL/HTTPS](https://docs.djangoproject.com/en/stable/topics/security/#security-recommendation-ssl) for more details.

#### SEE ALSO
* [`ENABLE_HTTPS`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-ENABLE_HTTPS)
* [Allowed hosts setup](#production-hosts)
* [Set correct site domain](#production-site)

### Set properly SECURE_HSTS_SECONDS

If your site is served over SSL, you have to consider setting a value for [`SECURE_HSTS_SECONDS`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SECURE_HSTS_SECONDS)
in the `settings.py` to enable HTTP Strict Transport Security.
By default it’s set to 0 as shown below.

```python
SECURE_HSTS_SECONDS = 0
```

If set to a non-zero integer value, the [`django.middleware.security.SecurityMiddleware`](https://docs.djangoproject.com/en/stable/ref/middleware/#django.middleware.security.SecurityMiddleware)
sets the [HTTP Strict Transport Security](https://docs.djangoproject.com/en/stable/ref/middleware/#http-strict-transport-security) header on all responses that do not already have it.

#### WARNING
Setting this incorrectly can irreversibly (for some time) break your site. Read the
[HTTP Strict Transport Security](https://docs.djangoproject.com/en/stable/ref/middleware/#http-strict-transport-security) documentation first.

<a id="production-database"></a>

### Use a powerful database engine

* Please use PostgreSQL for a production environment, see [Database setup for Weblate](#database-setup)
  for more info.
* Use adjacent location for running the database server, otherwise the networking
  performance or reliability might ruin your Weblate experience.
* Check the database server performance or tweak its configuration, for example
  using [PGTune](https://pgtune.leopard.in.ua/).
* Weblate deployment checks report non-finite PostgreSQL relation statistics.
  Run `ANALYZE` on the reported relations to rebuild corrupted statistics.

#### SEE ALSO
* [Database setup for Weblate](#database-setup)
* [Migrating from other databases to PostgreSQL](https://docs.weblate.org/no/latest/admin/upgrade.md#database-migration)
* [Adjusting configuration](#configuration)
* [Databases](https://docs.djangoproject.com/en/stable/ref/databases/)

<a id="production-cache"></a>

### Configure cache

If possible, use Valkey or Redis from Django by adjusting the `CACHES`
configuration variable, for example:

```python
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/0",
        # If redis is running on same host as Weblate, you might
        # want to use unix sockets instead:
        # 'LOCATION': 'unix:///var/run/redis/redis.sock?db=0',
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "PARSER_CLASS": "redis.connection.HiredisParser",
        },
    }
}
```

#### HINT
In case you change settings for the cache, you might need to adjust them for
Celery as well, see [Background tasks using Celery](#celery).

#### SEE ALSO
* [Avatar caching](#production-cache-avatar)
* [Django’s cache framework](https://docs.djangoproject.com/en/stable/topics/cache/)

<a id="production-cache-avatar"></a>

### Avatar caching

In addition to caching of Django, Weblate performs caching of avatars. It is
recommended to use a separate, file-backed cache for this purpose:

```python
CACHES = {
    "default": {
        # Default caching backend setup, see above
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "unix:///var/run/redis/redis.sock?db=0",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "PARSER_CLASS": "redis.connection.HiredisParser",
        },
    },
    "avatar": {
        "BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
        "LOCATION": os.path.join(DATA_DIR, "avatar-cache"),
        "TIMEOUT": 604800,
        "OPTIONS": {
            "MAX_ENTRIES": 1000,
        },
    },
}
```

#### SEE ALSO
* [`ENABLE_AVATARS`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-ENABLE_AVATARS)
* [`AVATAR_URL_PREFIX`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-AVATAR_URL_PREFIX)
* [Avatars](https://docs.weblate.org/no/latest/admin/optionals.md#avatars)
* [Configure cache](#production-cache)
* [Django’s cache framework](https://docs.djangoproject.com/en/stable/topics/cache/)

<a id="production-email"></a>

### Configure e-mail sending

Weblate needs to send out e-mails on several occasions, and these e-mails should
have a correct sender address, please configure [`SERVER_EMAIL`](#std-setting-SERVER_EMAIL) and
[`DEFAULT_FROM_EMAIL`](#std-setting-DEFAULT_FROM_EMAIL) to match your environment, for example:

```python
SERVER_EMAIL = "admin@example.org"
DEFAULT_FROM_EMAIL = "weblate@example.org"
```

#### NOTE
To disable sending e-mails by Weblate set [`EMAIL_BACKEND`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_BACKEND)
to `django.core.mail.backends.dummy.EmailBackend`.

This will disable *all* e-mail delivery including registration or password
reset e-mails.

#### SEE ALSO
* [Adjusting configuration](#configuration)
* [Configuring outgoing e-mail](#out-mail)
* [`EMAIL_BACKEND`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-EMAIL_BACKEND)
* [`DEFAULT_FROM_EMAIL`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-DEFAULT_FROM_EMAIL)
* [`SERVER_EMAIL`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-SERVER_EMAIL)

<a id="production-hosts"></a>

### Allowed hosts setup

Django requires [`ALLOWED_HOSTS`](#std-setting-ALLOWED_HOSTS) to hold a list of domain names
your site is allowed to serve, leaving it empty will block any requests.

In case this is not configured to match your HTTP server, you will get errors
like `Invalid HTTP_HOST header: '1.1.1.1'. You may need to add '1.1.1.1'
to ALLOWED_HOSTS.`

#### HINT
On Docker container, this is available as [`WEBLATE_ALLOWED_HOSTS`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_ALLOWED_HOSTS).

#### SEE ALSO
* [`ALLOWED_HOSTS`](#std-setting-ALLOWED_HOSTS)
* [`WEBLATE_ALLOWED_HOSTS`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_ALLOWED_HOSTS)
* [Set correct site domain](#production-site)

<a id="production-secret"></a>

### Django secret key

The [`SECRET_KEY`](#std-setting-SECRET_KEY) setting is used by Django to sign cookies, and you should
really generate your own value rather than using the one from the example setup.

You can generate a new key using **weblate-generate-secret-key** shipped
with Weblate.

#### SEE ALSO
[`SECRET_KEY`](#std-setting-SECRET_KEY)

<a id="production-cron"></a>

### Running maintenance tasks

For optimal performance, it is good idea to run some maintenance tasks in the
background. This is automatically done by [Background tasks using Celery](#celery) and covers following tasks:

* Configuration health check (hourly).
* Committing pending changes (hourly), see [Lazy commits](https://docs.weblate.org/no/latest/admin/continuous.md#lazy-commit) and [`commit_pending`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-commit_pending).
* Updating component alerts (daily).
* Update remote branches (nightly), see [`AUTO_UPDATE`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-AUTO_UPDATE).
* Translation memory backup to JSON (daily), see [`dump_memory`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-dump_memory).
* Fulltext and database maintenance tasks (daily and weekly tasks), see [`cleanuptrans`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-cleanuptrans).

<a id="production-encoding"></a>

### System locales and encoding

The system locales should be configured to UTF-8 capable ones. On most Linux
distributions this is the default setting. In case it is not the case on your
system, please change locales to UTF-8 variant.

For example by editing `/etc/default/locale` and setting there
`LANG="C.UTF-8"`.

In some cases the individual services have separate configuration for locales.
This varies between distribution and web servers, so check documentation of
your web server packages for that.

Apache on Ubuntu uses `/etc/apache2/envvars`:

```sh
export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'
```

Apache on CentOS uses `/etc/sysconfig/httpd` (or
`/opt/rh/httpd24/root/etc/sysconfig/httpd`):

```sh
LANG='en_US.UTF-8'
```

<a id="production-certs"></a>

### Using custom certificate authority

Weblate verifies SSL certificates during HTTP requests. Requests made using
HTTPX2 use the system certificate store, so install custom certificate
authorities there.

Check your distribution documentation for more details. For example, on Debian
this can be done by placing the CA certificate into
`/usr/local/share/ca-certificates/` and running
**update-ca-certificates**.

#### HINT
The Weblate container does not include it in the search path, you need to
specify full path to execute it. For example:

```sh
docker compose exec -u root weblate /usr/sbin/update-ca-certificates
```

Once this is done, Weblate HTTPX2 requests and system tools, including Git, will
trust the certificate.

Some integrations, including OAuth and OpenID Connect authentication, use
Requests, which does not use the system certificate store by default. When
these integrations communicate with services using the custom certificate
authority, configure Requests to use the system CA bundle by adding the
following to `settings.py` (the path is Debian-specific):

```python
import os

os.environ["REQUESTS_CA_BUNDLE"] = "/etc/ssl/certs/ca-certificates.crt"
```

<a id="server"></a>

## Running server

#### HINT
In case you are not experienced with services described below, you might want to try [Installing using Docker](https://docs.weblate.org/no/latest/admin/install/docker.md).

You will need several services to run Weblate, the recommended setup consists of:

* Database server (see [Database setup for Weblate](#database-setup))
* Cache server (see [Configure cache](#production-cache))
* Frontend web server for static files and SSL termination (see [Serving static files](#static-files))
* WSGI server for dynamic content (see [Sample configuration for NGINX and uWSGI](#uwsgi))
* Celery for executing background tasks (see [Background tasks using Celery](#celery))

#### NOTE
There are some dependencies between the services, for example cache and
database should be running when starting up Celery or uwsgi processes.

In most cases, you will run all services on single (virtual) server, but in
case your installation is heavy loaded, you can split up the services. The only
limitation on this is that Celery and Wsgi servers need access to
[`DATA_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-DATA_DIR).

#### NOTE
The WSGI process has to be executed under the same user the Celery
process, otherwise files in the [`DATA_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-DATA_DIR) will be stored with
mixed ownership, leading to runtime issues.

See also [Filesystem permissions](#file-permissions) and [Background tasks using Celery](#celery).

### Running web server

Running Weblate is not different from running any other Django based
program. Django is usually executed as WSGI or fcgi (see examples for
different webservers below).

#### NOTE
The sample configuration files shown below are maintained in the Weblate
source tree under `weblate/examples/`. They are included in source
distributions and in this documentation, but Python wheels only install
runtime files. When installing Weblate from PyPI, get the matching source
distribution or source checkout before copying these examples.

For testing purposes, you can use the built-in web server in Django:

```sh
weblate runserver
```

#### WARNING
DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through
security audits or performance tests. See also Django documentation on
[`runserver`](https://docs.djangoproject.com/en/stable/ref/django-admin/#django-admin-runserver).

#### HINT
The Django built-in server serves static files only with [`DEBUG`](#std-setting-DEBUG)
enabled as it is intended for development only. For production use, please
see WSGI setups:

* [Sample configuration for NGINX and Granian](#nginx-granian)
* [Sample configuration for NGINX and Gunicorn](#nginx-gunicorn)
* [Sample configuration for NGINX and uWSGI](#uwsgi)
* [Sample configuration for Apache](#apache)
* [Sample configuration for Apache and Gunicorn](#apache-gunicorn)
* [Serving static files](#static-files)

<a id="static-files"></a>

### Serving static files

#### Versionchanged
Changed in version 5.15.2: `/media/` is no longer used for serving screenshots.

Django needs to collect its static files in a single directory. To do so,
execute `weblate collectstatic --noinput`. This will copy the static
files into a directory specified by the [`STATIC_ROOT`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-STATIC_ROOT) setting (this defaults to
a `static` directory inside [`CACHE_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CACHE_DIR)). Production installations
use content hashes in collected filenames so that updated assets do not reuse
stale browser or proxy caches.

It is recommended to serve static files directly from your web server, you should
use that for the following paths:

`/static/`
: Serves static files for Weblate and the admin interface
  (from defined by [`STATIC_ROOT`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-STATIC_ROOT)).

`/favicon.ico`
: Should be rewritten to serve `/static/favicon.ico`.

#### SEE ALSO
* [Sample configuration for NGINX and Granian](#nginx-granian)
* [Sample configuration for NGINX and Gunicorn](#nginx-gunicorn)
* [Sample configuration for NGINX and uWSGI](#uwsgi)
* [Sample configuration for Apache](#apache)
* [Sample configuration for Apache and Gunicorn](#apache-gunicorn)
* [How to deploy Django](https://docs.djangoproject.com/en/stable/howto/deployment/)
* [How to deploy static files](https://docs.djangoproject.com/en/stable/howto/static-files/deployment/)

<a id="csp"></a>

### Content security policy

The default Weblate configuration enables `weblate.middleware.SecurityMiddleware`
middleware which sets security related HTTP headers like *Content-Security-Policy*
or *X-XSS-Protection*. These are by default set up to work with Weblate and its
configuration, but this might need customization for your environment.

#### SEE ALSO
* [`CSP_SCRIPT_SRC`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CSP_SCRIPT_SRC)
* [`CSP_IMG_SRC`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CSP_IMG_SRC)
* [`CSP_CONNECT_SRC`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CSP_CONNECT_SRC)
* [`CSP_STYLE_SRC`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CSP_STYLE_SRC)
* [`CSP_FONT_SRC`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CSP_FONT_SRC)
* [`CSP_FORM_SRC`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-CSP_FORM_SRC)

<a id="nginx-granian"></a>

### Sample configuration for NGINX and Granian

The following configuration runs Weblate using Granian with the NGINX webserver:

```nginx
#
# nginx configuration for Weblate
#
# You will want to change:
#
# - server_name
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change /home/weblate/data/cache to match your CACHE_DIR
# - change python3.12 to match your Python version
# - change weblate user to match your Weblate user
#
server {
    listen 80;
    server_name weblate;
    # Not used
    root /var/www/html;

    location ~ ^/favicon.ico$ {
        # CACHE_DIR/static/favicon.ico
        alias /home/weblate/data/cache/static/favicon.ico;
        expires 30d;
    }

    location /static/ {
        # CACHE_DIR/static/
        alias /home/weblate/data/cache/static/;
        expires 30d;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:8888;
        proxy_read_timeout 3600;
    }
}
```

#### SEE ALSO
* [Sample configuration to start Granian](#running-granian)
* [https://github.com/emmett-framework/granian](https://github.com/emmett-framework/granian)
* [How to deploy with WSGI](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/)

<a id="nginx-gunicorn"></a>

### Sample configuration for NGINX and Gunicorn

The following configuration runs Weblate using Gunicorn under the NGINX webserver
(`weblate/examples/weblate.nginx.gunicorn.conf` in the source tree):

```nginx
#
# nginx configuration for Weblate
#
# You will want to change:
#
# - server_name
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change /home/weblate/data/cache to match your CACHE_DIR
# - change python3.12 to match your Python version
# - change weblate user to match your Weblate user
#
server {
    listen 80;
    server_name weblate;
    # Not used
    root /var/www/html;

    location ~ ^/favicon.ico$ {
        # CACHE_DIR/static/favicon.ico
        alias /home/weblate/data/cache/static/favicon.ico;
        expires 30d;
    }

    location /static/ {
        # CACHE_DIR/static/
        alias /home/weblate/data/cache/static/;
        expires 30d;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_pass http://unix:/run/gunicorn.sock;
        proxy_read_timeout 3600;
    }
}
```

#### SEE ALSO
* [Sample configuration to start Gunicorn](#running-gunicorn)
* [How to use Django with Gunicorn](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/gunicorn/)

<a id="uwsgi"></a>

### Sample configuration for NGINX and uWSGI

To run production webserver, use the WSGI wrapper installed with Weblate (when
using a Python environment it is installed as
`~/weblate-env/lib/python3.14/site-packages/weblate/wsgi.py`). Don’t
forget to set the Python search path to your Python environment as well (for
example using `virtualenv = /home/user/weblate-env` in uWSGI).

The following configuration runs Weblate as uWSGI under the NGINX webserver.

Configuration for NGINX (`weblate/examples/weblate.nginx.conf` in the source tree):

```nginx
#
# nginx configuration for Weblate
#
# You will want to change:
#
# - server_name
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change /home/weblate/data/cache to match your CACHE_DIR
# - change python3.12 to match your Python version
# - change weblate user to match your Weblate user
#
server {
    listen 80;
    server_name weblate;
    # Not used
    root /var/www/html;

    location ~ ^/favicon.ico$ {
        # CACHE_DIR/static/favicon.ico
        alias /home/weblate/data/cache/static/favicon.ico;
        expires 30d;
    }

    location /static/ {
        # CACHE_DIR/static/
        alias /home/weblate/data/cache/static/;
        expires 30d;
    }

    location / {
        include uwsgi_params;
        # Needed for long running operations in admin interface
        uwsgi_read_timeout 3600;
        # Adjust based to uwsgi configuration:
        uwsgi_pass unix:///run/uwsgi/app/weblate/socket;
        # uwsgi_pass 127.0.0.1:8080;
    }
}
```

Configuration for uWSGI (`weblate/examples/weblate.uwsgi.ini` in the source tree):

```ini
#
# uWSGI configuration for Weblate
#
# You will want to change:
#
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change python3.12 to match your Python version
# - change weblate user to match your Weblate user
#
[uwsgi]
plugins       = python3
master        = true
protocol      = uwsgi
socket        = 127.0.0.1:8080
wsgi-file     = /home/weblate/weblate-env/lib/python3.12/site-packages/weblate/wsgi.py

# Add path to Weblate checkout if you did not install
# Weblate by pip
# python-path   = /path/to/weblate

# Path to the Python environment
virtualenv = /home/weblate/weblate-env

# Set sys.executable so Python helpers run with the virtual environment's Python
py-executable = /home/weblate/weblate-env/bin/python

# Needed for OAuth/OpenID
buffer-size   = 8192

# Reload when consuming too much of memory
reload-on-rss = 250

# Increase number of workers for heavily loaded sites
workers       = 8

# Enable threads for Sentry error submission
enable-threads = true

# Child processes do not need file descriptors
close-on-exec = true

# Avoid default 0000 umask
umask = 0022

# Run as weblate user
uid = weblate
gid = weblate

# Enable harakiri mode (kill requests after some time)
# harakiri = 3600
# harakiri-verbose = true

# Enable uWSGI stats server
# stats = :1717
# stats-http = true

# Do not log some errors caused by client disconnects
ignore-sigpipe = true
ignore-write-errors = true
disable-write-exception = true
```

Set `py-executable` to the absolute path of `bin/python` inside the
environment configured by `virtualenv`. Weblate uses Python’s
`sys.executable` to launch helper processes, including the SSH connection
proxy used for Git repositories. uWSGI can otherwise set this value to its own
executable, causing repository operations to fail with an error such as
`/usr/bin/uwsgi-core: invalid option -- 'I'`. Setting `virtualenv` alone does
not ensure that `sys.executable` points to Python. Restart uWSGI after updating
the configuration.

#### SEE ALSO
[How to use Django with uWSGI](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/uwsgi/)

<a id="apache"></a>

### Sample configuration for Apache

It is recommended to use prefork MPM when using WSGI with Weblate.

The following configuration runs Weblate as WSGI, you need to have enabled
`mod_wsgi` (`weblate/examples/apache.conf` in the source tree):

```apache
#
# VirtualHost for Weblate
#
# You will want to change:
#
# - ServerAdmin and ServerName
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change /home/weblate/data/cache to match your CACHE_DIR
# - change python3.12 to match Python version mod-wsgi is compiled for
# - change weblate user to match your Weblate user
#
<VirtualHost *:80>
    ServerAdmin admin@weblate.example.org
    ServerName weblate.example.org

    # CACHE_DIR/static/favicon.ico
    Alias /favicon.ico /home/weblate/data/cache/static/favicon.ico

    # CACHE_DIR/static/
    Alias /static/ /home/weblate/data/cache/static/
    <Directory /home/weblate/data/cache/static/>
        Require all granted
    </Directory>

    # Path to your Weblate Python environment
    WSGIDaemonProcess weblate python-home=/home/weblate/weblate-env user=weblate request-timeout=600
    WSGIProcessGroup weblate
    WSGIApplicationGroup %{GLOBAL}

    WSGIScriptAlias / /home/weblate/weblate-env/lib/python3.12/site-packages/weblate/wsgi.py process-group=weblate
    WSGIPassAuthorization On

    <Directory /home/weblate/weblate-env/lib/python3.12/site-packages/weblate/>
        <Files wsgi.py>
        Require all granted
        </Files>
    </Directory>

</VirtualHost>
```

#### NOTE
Weblate requires Python 3, so please ensure you are running Python 3
variant of the modwsgi. Usually it is available as a separate package, for
example `libapache2-mod-wsgi-py3`.

Use matching Python version to install Weblate.

#### SEE ALSO
* [System locales and encoding](#production-encoding)
* [How to use Django with Apache and mod_wsgi](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/modwsgi/)

<a id="apache-gunicorn"></a>

### Sample configuration for Apache and Gunicorn

The following configuration runs Weblate in Gunicorn and Apache 2.4
(`weblate/examples/apache.gunicorn.conf` in the source tree):

```apache
#
# VirtualHost for Weblate using gunicorn on localhost:8000
#
# You will want to change:
#
# - ServerAdmin and ServerName
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change /home/weblate/data/cache to match your CACHE_DIR
# - change weblate user to match your Weblate user
#
<VirtualHost *:443>
    ServerAdmin admin@weblate.example.org
    ServerName weblate.example.org

    # CACHE_DIR/static/favicon.ico
    Alias /favicon.ico /home/weblate/data/cache/static/favicon.ico

    # CACHE_DIR/static/
    Alias /static/ /home/weblate/data/cache/static/
    <Directory /home/weblate/data/cache/static/>
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/https_cert.cert
    SSLCertificateKeyFile /etc/apache2/ssl/https_key.pem
    SSLProxyEngine On

    ProxyPass /favicon.ico !
    ProxyPass /static/ !

    ProxyPass / http://localhost:8000/
    ProxyPassReverse / http://localhost:8000/
    ProxyPreserveHost On
</VirtualHost>
```

#### SEE ALSO
* [Sample configuration to start Gunicorn](#running-gunicorn)
* [How to use Django with Gunicorn](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/gunicorn/)

<a id="running-granian"></a>

### Sample configuration to start Granian

Weblate has wsgi optional dependency (see [Python dependencies](#python-deps)) that will
install everything you need to run Granian. When installing Weblate you can specify it as:

```shell
uv pip install Weblate[all,wsgi]
```

Once you have Granian installed, you can run it. This is usually done at the
system level. The following examples show starting via systemd:

```ini
[Unit]
Description=granian daemon
After=network.target

[Service]
User=weblate
Group=weblate
WorkingDirectory=/home/weblate/weblate-env/
Environment="DJANGO_SETTINGS_MODULE=weblate.settings"
RuntimeDirectory=granian
ExecStart=/home/weblate/weblate-env/bin/granian \
    --no-ws \
    --workers-max-rss 450 \
    --interface wsgi \
    --workers 2 \
    --blocking-threads 8 \
    --backlog 128 \
    --backpressure 16 \
    --runtime-mode mt \
    --port 8888 \
    weblate.wsgi:application

[Install]
WantedBy=multi-user.target
```

Granian uses worker processes for parallel Python execution, blocking threads
for concurrent WSGI requests, and runtime threads for network I/O. The sample
uses two workers with eight blocking threads each, limits each worker to 16
concurrent connections, and leaves the runtime threads at Granian’s default.
Adjust the workers and blocking threads to the available memory, CPU cores, and
database connection limit. Keep the backpressure equal to or higher than the
number of blocking threads.

#### SEE ALSO
* [Sample configuration to start Granian with ASGI](#running-granian-asgi)
* [https://github.com/emmett-framework/granian](https://github.com/emmett-framework/granian)
* [How to deploy with WSGI](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/)

<a id="running-granian-asgi"></a>

### Sample configuration to start Granian with ASGI

#### Versionadded
Added in version 2026.8.

ASGI deployment is available as an opt-in alternative to WSGI. Install the
`asgi` optional dependency:

```shell
uv pip install Weblate[all,asgi]
```

The following systemd unit runs the Django ASGI application:

```ini
[Unit]
Description=granian ASGI daemon
After=network.target

[Service]
User=weblate
Group=weblate
WorkingDirectory=/home/weblate/weblate-env/
Environment="DJANGO_SETTINGS_MODULE=weblate.settings"
RuntimeDirectory=granian
ExecStart=/home/weblate/weblate-env/bin/granian \
    --no-ws \
    --workers-max-rss 450 \
    --interface asginl \
    --workers 2 \
    --backlog 128 \
    --backpressure 16 \
    --runtime-mode mt \
    --port 8888 \
    weblate.asgi:application

[Install]
WantedBy=multi-user.target
```

The sample uses Granian’s ASGI interface without lifespan or WebSocket support,
because Weblate currently exposes HTTP only. Weblate’s middleware supports both
deployment modes and uses thread-sensitive adapters where it still relies on
synchronous Django APIs. The health check is asynchronous, but most Weblate
views remain synchronous, and CPU-intensive or long-running work should still
be handled by [Background tasks using Celery](#celery).

WSGI remains the default deployment mode. Docker images can opt in to ASGI by
setting [`WEBLATE_ASGI`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_ASGI) to `1`. Adjust the worker count and
backpressure to the available memory, CPU cores, and database connection limit.

#### SEE ALSO
* [Sample configuration to start Granian](#running-granian)
* [https://github.com/emmett-framework/granian](https://github.com/emmett-framework/granian)
* [How to deploy with ASGI](https://docs.djangoproject.com/en/stable/howto/deployment/asgi/)

<a id="running-gunicorn"></a>

### Sample configuration to start Gunicorn

Gunicorn has to be installed separately:

```shell
uv pip install gunicorn
```

Once you have Gunicorn installed, you can run it. This is usually done at the
system level. The following examples show starting via systemd:

```ini
[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target
```

```ini
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=weblate
Group=weblate
WorkingDirectory=/home/weblate/weblate-env/
Environment="DJANGO_SETTINGS_MODULE=weblate.settings"
ExecStart=/home/weblate/weblate-env/bin/gunicorn \
    --preload \
    --timeout 3600 \
    --graceful-timeout 3600 \
    --worker-class=gthread \
    --workers=2 \
    --threads=16 \
    --bind unix:/run/gunicorn.sock \
    weblate.wsgi:application

[Install]
WantedBy=multi-user.target
```

#### SEE ALSO
[How to use Django with Gunicorn](https://docs.djangoproject.com/en/stable/howto/deployment/wsgi/gunicorn/)

### Running Weblate under path

It is recommended to use prefork MPM when using WSGI with Weblate.

A sample Apache configuration to serve Weblate under `/weblate`. Again using
`mod_wsgi` (`weblate/examples/apache-path.conf` in the source tree):

```apache
#
# VirtualHost for Weblate, running under /weblate path
#
# You will want to change:
#
# - ServerAdmin and ServerName
# - change /home/weblate/weblate-env to location where Weblate Python environment is placed
# - change /home/weblate/data to match your DATA_DIR
# - change /home/weblate/data/cache to match your CACHE_DIR
# - change python3.12 to match Python version mod-wsgi is compiled for
# - change weblate user to match your Weblate user
#
<VirtualHost *:80>
    ServerAdmin admin@weblate.example.org
    ServerName weblate.example.org

    # CACHE_DIR/static/favicon.ico
    Alias /weblate/favicon.ico /home/weblate/data/cache/static/favicon.ico

    # CACHE_DIR/static/
    Alias /weblate/static/ /home/weblate/data/cache/static/
    <Directory /home/weblate/data/cache/static/>
        Require all granted
    </Directory>

    # Path to your Weblate Python environment
    WSGIDaemonProcess weblate python-home=/home/weblate/weblate-env user=weblate request-timeout=600
    WSGIProcessGroup weblate
    WSGIApplicationGroup %{GLOBAL}

    WSGIScriptAlias /weblate /home/weblate/weblate-env/lib/python3.12/site-packages/weblate/wsgi.py process-group=weblate
    WSGIPassAuthorization On

    <Directory /home/weblate/weblate-env/lib/python3.12/site-packages/weblate/>
        <Files wsgi.py>
        Require all granted
        </Files>
    </Directory>

</VirtualHost>
```

Additionally, you will have to adjust `weblate/settings.py`:

```python
URL_PREFIX = "/weblate"
```

<a id="celery"></a>

## Background tasks using Celery

Weblate uses Celery to execute regular and background tasks. You are supposed
to run a Celery service that will execute these. For example, it is responsible
for handling following operations (this list is not complete):

* Receiving webhooks from external services (see [Notification hooks](https://docs.weblate.org/no/latest/api.md#hooks)).
* Running regular maintenance tasks such as backups, cleanups, daily add-ons, or updates
  (see [Backing up and moving Weblate](https://docs.weblate.org/no/latest/admin/backup.md#backup), [`BACKGROUND_TASKS`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-BACKGROUND_TASKS), [Add-ons](https://docs.weblate.org/no/latest/admin/addons.md#addons)).
* Running [Automatic translation](https://docs.weblate.org/no/latest/user/translating.md#auto-translation).
* Sending digest notifications.
* Offloading expensive operations from the WSGI process.
* Committing pending changes (see [Lazy commits](https://docs.weblate.org/no/latest/admin/continuous.md#lazy-commit)).

A typical setup using Valkey or Redis as a backend looks like this:

```python
CELERY_TASK_ALWAYS_EAGER = False
CELERY_BROKER_URL = "redis://localhost:6379"
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
```

#### SEE ALSO
[Redis broker configuration in Celery](https://docs.celeryq.dev/en/stable/getting-started/backends-and-brokers/redis.html#broker-redis-configuration)

You should also start the Celery worker to process the tasks and start scheduled
tasks. For debugging or development, this can be done directly on the
command-line:

```sh
celery --app=weblate.utils worker --beat \
    --queues=celery,notify,memory,translate,backup \
    --prefetch-multiplier=1
```

Running all queues in one prefork worker shares the initial application memory
between its child processes while retaining parallel task execution. Celery
determines the concurrency from the number of available CPUs by default; use
`--concurrency` to adjust it for your workload and available memory.

To reduce startup memory usage, Celery workers do not repeat the Django system
checks. The Weblate container runs the more comprehensive
**weblate check --deploy** automatically during container startup. For
other installation methods, run the command after installation, upgrades, or
configuration changes. The checks are also available in the
[management interface](https://docs.weblate.org/no/latest/admin/admin.md#manage-performance).

#### NOTE
The Celery process has to be executed under the same user as the WSGI
process, otherwise files in the [`DATA_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-DATA_DIR) will be stored with
mixed ownership, leading to runtime issues.

See also [Filesystem permissions](#file-permissions) and [Running server](#server).

### Executing Celery tasks in the WSGI using eager mode

#### NOTE
This will have severe performance impact on the web interface, and will
break features depending on regular trigger (for example committing pending
changes, digest notifications, or backups).

For development, you might want to use eager configuration, which does process
all tasks in place:

```python
CELERY_TASK_ALWAYS_EAGER = True
CELERY_BROKER_URL = "memory://"
CELERY_TASK_EAGER_PROPAGATES = True
```

### Running Celery as system service

Most likely you will want to run Celery as a daemon and that is covered by
[Daemonization](https://docs.celeryq.dev/en/stable/userguide/daemonizing.html). For the most common Linux setup using
systemd, adapt the example files listed below. These examples are maintained in
the Weblate source tree under `weblate/examples/`; Python wheels do not
install these deployment samples.

Systemd unit to be placed as `/etc/systemd/system/celery-weblate.service`:

```ini
[Unit]
Description=Celery Service (Weblate)
After=network.target

[Service]
Type=forking
User=weblate
Group=weblate
EnvironmentFile=/etc/default/celery-weblate
WorkingDirectory=/home/weblate
RuntimeDirectory=celery
RuntimeDirectoryPreserve=restart
LogsDirectory=celery
ExecStart=/bin/sh -c '${CELERY_BIN} multi start ${CELERYD_NODES} \
  -A ${CELERY_APP} --pidfile=${CELERYD_PID_FILE} \
  --logfile=${CELERYD_LOG_FILE} --loglevel=${CELERYD_LOG_LEVEL} ${CELERYD_OPTS}'
ExecStop=/bin/sh -c '${CELERY_BIN} multi stopwait ${CELERYD_NODES} \
  --pidfile=${CELERYD_PID_FILE}'
ExecReload=/bin/sh -c '${CELERY_BIN} multi restart ${CELERYD_NODES} \
  -A ${CELERY_APP} --pidfile=${CELERYD_PID_FILE} \
  --logfile=${CELERYD_LOG_FILE} --loglevel=${CELERYD_LOG_LEVEL} ${CELERYD_OPTS}'

[Install]
WantedBy=multi-user.target
```

Environment configuration to be placed as `/etc/default/celery-weblate`:

```sh
# Name of nodes to start
CELERYD_NODES="combined"

# Absolute or relative path to the 'celery' command:
CELERY_BIN="/home/weblate/weblate-env/bin/celery"

# App instance to use
# comment out this line if you don't use an app
CELERY_APP="weblate.utils"

# Extra command-line arguments to the worker. Celery determines concurrency
# from the number of available CPUs by default. You might need to customize it
# depending on the available resources and Weblate usage. Increase concurrency
# if you get weblate.E019 error, decrease it on a low-resource system.
# Command-line values override corresponding Celery settings in settings.py.
CELERYD_OPTS="--beat:combined --queues:combined=celery,notify,memory,translate,backup --prefetch-multiplier:combined=1"

# Logging configuration
# - %n will be replaced with the first part of the nodename.
# - %I will be replaced with the current child process index
#   and is important when using the prefork pool to avoid race conditions.
CELERYD_PID_FILE="/run/celery/weblate-%n.pid"
CELERYD_LOG_FILE="/var/log/celery/weblate-%n%I.log"
CELERYD_LOG_LEVEL="INFO"
```

Additional configuration to rotate Celery logs using **logrotate** to be
placed as `/etc/logrotate.d/celery`:

```text
/var/log/celery/*.log {
        weekly
        missingok
        rotate 12
        compress
        notifempty
}
```

### Periodic tasks using Celery beat

Weblate comes with built-in setup for scheduled tasks. The task schedule is
stored in the database and tasks are executed by the Celery beat daemon.

#### HINT
You can define additional tasks in `settings.py`, for example see
[Lazy commits](https://docs.weblate.org/no/latest/admin/continuous.md#lazy-commit).

<a id="monitoring-celery"></a>

### Monitoring Celery status

You can find current length of the Celery task queues in the
[Management interface](https://docs.weblate.org/no/latest/admin/admin.md#management-interface) or you can use [`celery_queues`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-celery_queues) on the
command-line. In case the queue will get too long, you will also get
configuration error in the admin interface.

#### WARNING
The Celery errors are by default only logged into Celery log and are not
visible to user. In case you want to have overview on such failures, it is
recommended to configure [Collecting error reports and monitoring performance](#collecting-errors).

#### SEE ALSO
* [Monitoring Weblate](#monitoring)
* [How can I check whether my Weblate is set up properly?](https://docs.weblate.org/no/latest/faq.md#faq-monitoring)
* [Configuration and defaults](https://docs.celeryq.dev/en/stable/userguide/configuration.html)
* [Workers Guide](https://docs.celeryq.dev/en/stable/userguide/workers.html)
* [Daemonization](https://docs.celeryq.dev/en/stable/userguide/daemonizing.html)
* [Monitoring and Management Guide](https://docs.celeryq.dev/en/stable/userguide/monitoring.html)
* [Background tasks internals](https://docs.weblate.org/no/latest/contributing/internals.md#background-tasks-internals)
* [`celery_queues`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-celery_queues)

<a id="minimal-celery"></a>

### Single-process Celery setup

In case you have very limited memory, you might want to reduce number of
Weblate processes. All Celery tasks can be executed in a single process using:

```sh
celery --app=weblate.utils worker --beat --queues=celery,notify,memory,translate,backup --pool=solo
```

An installation using Docker can be configured to use a single-process Celery
setup by setting `CELERY_WORKER_MODE=single`. See
[`CELERY_WORKER_MODE`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-CELERY_WORKER_MODE).

#### WARNING
This will have a noticeable performance impact on Weblate.

<a id="monitoring"></a>

## Monitoring Weblate

Weblate provides the `/healthz/` URL to be used in simple health checks, for example
using Kubernetes. The Docker container has built-in health check using this URL.

For monitoring metrics of Weblate you can use the [`GET /api/metrics/`](https://docs.weblate.org/no/latest/api.md#get--api-metrics-) API
endpoint. Monitoring tools running locally can retrieve the same metrics using
the [`metrics`](https://docs.weblate.org/no/latest/admin/management.md#weblate-admin-metrics) command.

#### SEE ALSO
* [How can I check whether my Weblate is set up properly?](https://docs.weblate.org/no/latest/faq.md#faq-monitoring)
* [Monitoring Celery status](#monitoring-celery)
* [Weblate plugin for Munin](https://github.com/WeblateOrg/munin)

<a id="collecting-errors"></a>

## Collecting error reports and monitoring performance

Weblate, as any other software, can fail. In order to collect useful failure
states we recommend to use third party services to collect such information.
This is especially useful in case of failing Celery tasks, which would
otherwise only report error to the logs and you won’t get notified on them.
Weblate has support for the following services:

### E-mail

The default Weblate configuration instruments Django to send e-mails upon
server errors via [`django.utils.log.AdminEmailHandler`](https://docs.djangoproject.com/en/stable/ref/logging/#django.utils.log.AdminEmailHandler). This
is the least effort setup, but you should consider other options for privacy
reasons, as the error e-mails might include sensitive data. You can read more on
that in [Security implications](https://docs.djangoproject.com/en/stable/topics/logging/#logging-security-implications).

To disable this behavior, remove `mail_admins` from the
[`LOGGING`](https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-LOGGING) in Weblate settings, or disable
[`WEBLATE_ADMIN_NOTIFY_ERROR`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_ADMIN_NOTIFY_ERROR) in the Docker environment.

### Sentry

Weblate has built-in support for [Sentry](https://sentry.io/). To use
it, it’s enough to set [`SENTRY_DSN`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SENTRY_DSN) in the `settings.py`:

```python
SENTRY_DSN = "https://id@your.sentry.example.com/"
```

Sentry can be also used to monitor performance of Weblate by collecting traces
and profiles for defined percentage of operations. This can be configured using
[`SENTRY_TRACES_SAMPLE_RATE`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SENTRY_TRACES_SAMPLE_RATE) and [`SENTRY_PROFILES_SAMPLE_RATE`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-SENTRY_PROFILES_SAMPLE_RATE).

#### SEE ALSO
* [Sentry Performance Monitoring](https://docs.sentry.io/product/sentry-basics/performance-monitoring/)
* [Sentry Profiling](https://docs.sentry.io/product/profiling/)

### Google Cloud Error Reporting

Weblate can report handled server errors to [Google Cloud Error Reporting](https://docs.cloud.google.com/error-reporting/docs/grouping-errors).
Install Weblate with the `google-errors` extra and configure
[`GOOGLE_CLOUD_ERROR_REPORTING`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-GOOGLE_CLOUD_ERROR_REPORTING) in `settings.py`:

```python
GOOGLE_CLOUD_ERROR_REPORTING = {
    "project": "your-google-cloud-project",
}
```

Weblate automatically reports errors under the `weblate` service and uses the
current Weblate version or Git revision as the reported version. These values
can be overridden by setting `service` or `version` in
[`GOOGLE_CLOUD_ERROR_REPORTING`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-GOOGLE_CLOUD_ERROR_REPORTING).

### OpenTelemetry

Weblate can export backend traces using [OpenTelemetry](https://opentelemetry.io/).
It uses OTLP over HTTP and can send traces to an OpenTelemetry Collector or a
compatible vendor endpoint.

```python
OPENTELEMETRY_ENABLED = True
OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT = "https://collector.example.com/v1/traces"
OPENTELEMETRY_TRACES_SAMPLE_RATE = 0.1
```

The integration traces Django requests, Celery tasks, Redis, outgoing HTTP
requests, database calls, and Weblate-specific spans. Configure it using
[`OPENTELEMETRY_ENABLED`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-OPENTELEMETRY_ENABLED),
[`OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-OPENTELEMETRY_EXPORTER_OTLP_ENDPOINT), and
[`OPENTELEMETRY_TRACES_SAMPLE_RATE`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-OPENTELEMETRY_TRACES_SAMPLE_RATE).

<a id="rollbar-errors"></a>

### Rollbar

Weblate has built-in support for [Rollbar](https://rollbar.com/). To use
it, it’s enough to follow instructions for [Rollbar notifier for Python](https://docs.rollbar.com/docs/python/).

In short, you need to adjust `settings.py`:

```python
# Add rollbar as last middleware:
MIDDLEWARE = [
    # … other middleware classes …
    "rollbar.contrib.django.middleware.RollbarNotifierMiddleware",
]

# Configure client access
ROLLBAR = {
    "access_token": "POST_SERVER_ITEM_ACCESS_TOKEN",
    "environment": "development" if DEBUG else "production",
    "branch": "main",
    "root": "/absolute/path/to/code/root",
}
```

Everything else is integrated automatically, you will now collect both server
and client side errors.

#### NOTE
Error logging also includes exceptions that were gracefully handled, but
might indicate a problem - such as failed parsing of an uploaded file.

<a id="graylog"></a>

### Graylog log management

#### Versionadded
Added in version 5.9.

Weblate can be configured to log using the GELF TCP protocol. This was developed
for Graylog integration, but can be used with any compliant logging platform.

The configuration boilerplate is included in [Sample configuration](https://docs.weblate.org/no/latest/admin/sample.md#sample-configuration), for
Docker this can be configured using [`WEBLATE_LOG_GELF_HOST`](https://docs.weblate.org/no/latest/admin/install/docker.md#envvar-WEBLATE_LOG_GELF_HOST).

## Migrating Weblate to another server

Migrating Weblate to another server should be pretty easy, however it stores
data in few locations which you should migrate carefully. The best approach is
to stop Weblate for the migration.

### Migrating database

The most straightforward approach is to use database native tools, as they are
usually the most effective (e.g. **pg_dump**). Alternatively you can use
replication if your database supports it.

#### SEE ALSO
Migrating between databases described in [Migrating from other databases to PostgreSQL](https://docs.weblate.org/no/latest/admin/upgrade.md#database-migration).

### Migrating VCS repositories

The VCS repositories stored under [`DATA_DIR`](https://docs.weblate.org/no/latest/admin/config.md#std-setting-DATA_DIR) need to be migrated as
well. You can simply copy them or use **rsync** to do the migration
more effectively.

### Other notes

Don’t forget to move other services Weblate might have been using like
Valkey, Redis, Cron jobs or custom authentication backends.
