Important setup steps
Email setup
Forgejo can be set to send emails such as a registration confirmation, either with Sendmail (or compatible MTAs like Postfix and msmtp) or by connecting to an SMTP server.
Using SMTP
Directly use SMTP server as relay. This option is useful if you don't want to set up MTA on your instance but you have an account at an email provider.
[mailer]
ENABLED = true
FROM = forgejo@example.com
PROTOCOL = smtps
SMTP_ADDR = mail.example.com
SMTP_PORT = 465
USER = forgejo@example.com
PASSWD = `mysecurepassword`
Restart Forgejo for the configuration changes to take effect.
To send a test email to validate the settings, go to Forgejo > Site Administration > Configuration > SMTP Mailer Configuration.
To enable users to receive email notifications for pull requests or issues, you can set ENABLE_NOTIFY_MAIL=true in the configuration.
For the full list of options check the Config Cheat Sheet.
[!note] Note Authentication is only supported when the SMTP server communication is encrypted with TLS or
HOST=localhost. This is due to protections imposed by the Go internal libraries against STRIPTLS attacks. TLS encryption can be through:
- STARTTLS (also known as Opportunistic TLS) via port 587. Initial connection is done over cleartext, but then be upgraded over TLS if the server supports it.
- SMTPS connection (SMTP over TLS) via
SMTP_PORT=465and/orPROTOCOL=smtps. Connections to the server use TLS from the beginning, also known as Implicit TLS. It is recommended by RFC8314.
Using Sendmail
Use sendmail command as mailer.
[!note] Note For Internet-facing sites consult the documentation of your MTA for instructions to send emails over TLS. Also set up SPF, DMARC, and DKIM DNS records to make emails sent be accepted as legitimate by various email providers.
[mailer]
ENABLED = true
FROM = forgejo@example.com
PROTOCOL = sendmail
SENDMAIL_PATH = /usr/sbin/sendmail
SENDMAIL_ARGS = "--" ; most "sendmail" programs take options, "--" will prevent an email address being interpreted as an option.
Reverse proxy
Forgejo can live standalone, or behind a reverse proxy.
You may want this for scenarios like:
- Subpath mapping.
If you want Forgejo at something likehttps://example.com/code/orhttps://example.com/repositories/instead of the defaulthttps://example.com. - Port mapping.
If you want to run Forgejo on the standard port, and that port is already taken by another web server.
I.e. ashttps://example.cominstead of ashttps://example.com:3000. - Proxy authentication.
Using an external login service.
Forgejo usually does not need a proxy for this, as it can be configured to talk to many login services directly. - rate limiting.
Fail2ban allows to rate-limit TCP connections, but with a load-balancer you can inspect the headers, perform User-Agent detection, match the information provided by an ACL - advanced security settings.
Using a load balancer you can apply Content Security policies, tweak your SSL ciphers, and configure a Web Application Firewall. - caching and resilience.
load-balancers offer both caching and robustness. For instance, Haproxy can handle millions of simultaneous connections, and caching alleviates the load on the application.
Forgejo does not need the help of a proxy to do HTTPS, it can do it directly.
Set in SERVER section of the configuration PROTOCOL=https and either set CERT_FILE and KEY_FILE or let Forgejo manage the certificates with ENABLE_ACME=true
Security of subpath
The security model of browsers assumes that interactions on the same-origin are safe.[^1] By using a subpath, this assumption of the browser no longer holds, which can can make using Forgejo insecure if that origin hosts content entered by a user under different sub-paths. Forgejo offers no protection to mitigate this scenario. For example, malicious content on the same origin could host CSRF attacks against Forgejo.
[^1]: A good read about this security model is https://educatedguesswork.org/posts/web-security-model-origin.
NGINX
Basic HTTP
To set up a basic HTTP reverse proxy in nginx, create a file forgejo.conf in /etc/nginx/conf.d and add the following configuration:
server {
listen 80; # Listen on IPv4 port 80
listen [::]:80; # Listen on IPv6 port 80
server_name git.example.com; # Change this to the server domain name.
merge_slashes off; # Required to handle URL-encoded slashes
location / {
proxy_pass http://127.0.0.1:3000; # Port 3000 is the default Forgejo port
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 512M;
}
}
Make sure to reload/restart nginx after changing the configuration.
HTTP with a subpath
If you want to serve Forgejo on a subpath, e.g. on http://example.com/code, use the following configuration:
server {
listen 80; # Listen on IPv4 port 80
listen [::]:80; # Listen on IPv6 port 80
server_name example.com; # Change this to the server domain name.
merge_slashes off; # Required to handle URL-encoded slashes
location /code/ { # Replace /code here with your subpath
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Connection $http_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 512M;
}
}
Make sure to set the Forgejo ROOT_URL configuration key to the URL with the subpath, otherwise links generated by Forgejo will be broken.
HTTPS
When using a reverse proxy, it's usually easier to let the proxy handle HTTPS. It's easy to set up HTTPS on nginx.
HTTPS with Certbot
To set up HTTPS with Certbot, first set up an HTTP reverse proxy with the configuration above and ensure that it works as expected. To use HTTPS you need to have a domain name.
Then, install certbot. When running certbot, select the domain name that your Forgejo instance is hosted under, and choose automatic installation. This should automatically set up HTTPS on port 443 and a redirect on the old port 80.
You may wish to change the ROOT_URL configuration key to the HTTPS protocol so links generated by Forgejo automatically use HTTPS.
HTTPS with manually installed certificates
If you have obtained certificates from elsewhere or have chosen not to let Certbot automatically install them, make the following changes to the configuration file:
Change the listening ports
Change the lines
listen 80;
listen [::]:80;
to
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
Add the SSL certificate information
Generate an SSL configuration at mozilla, and add the SSL parameters to your configuration file. Make sure to replace the paths in the example with paths to your certificate files.
Add a redirect from HTTP
Outside the server block, add this redirection block:
server {
listen 80 default_server;
listen [::]:80 default_server;
location / {
return 301 https://$host$request_uri;
}
}
This will redirect anyone visiting the HTTP site to the HTTPS site.
Apache
Basic HTTP
To set up a basic HTTP proxy in Apache, create a file 100-forgejo.conf in /etc/apache2/sites-available and add the following configuration:
<VirtualHost *:80>
ServerName git.example.com
ProxyPreserveHost On
ProxyRequests off
AllowEncodedSlashes NoDecode
ProxyPass / http://127.0.0.1:3000/ nocanon
</VirtualHost>
Next, enable the site with a2ensite 100-forgejo.conf and enable the proxy modules with a2enmod proxy proxy_http. Finally, restart the Apache server.
HTTP with a subpath
If you want to serve Forgejo on a subpath, e.g. on http://example.com/code, use the following configuration:
<VirtualHost *:80>
ServerName example.com
ProxyPreserveHost On
ProxyRequests off
AllowEncodedSlashes NoDecode
ProxyPass /code http://127.0.0.1:3000/ nocanon # Change /code here to your desired subpath.
</VirtualHost>
Make sure to set the Forgejo ROOT_URL configuration key to the URL with the subpath, otherwise links generated by Forgejo will be broken.
HTTPS
When using a reverse proxy, it's usually easier to let the proxy handle HTTPS. It's easy to set up HTTPS on Apache.
HTTPS with Certbot
To set up HTTPS with Certbot, first set up an HTTP reverse proxy with the configuration above and ensure that it works as expected. To use HTTPS you need to have a domain name.
Then, install certbot. When running certbot, select the domain name that your Forgejo instance is hosted under, and choose automatic installation. This should automatically set up HTTPS on port 443 and a redirect on the old port 80.
You may wish to change the ROOT_URL configuration key to the HTTPS protocol so links generated by Forgejo automatically use HTTPS.
HTTPS with manually installed certificates
If you have obtained certificates from elsewhere or have chosen not to let certbot automatically install them, make the following changes to the configuration file:
Change the listening ports
Change <VirtualHost *:80> to <VirtualHost *:443>.
Add the SSL certificate information
Generate an SSL configuration at mozilla, and add the SSL parameters to your configuration file. Make sure to replace the paths in the example with paths to your certificate files.
Add a redirect from HTTP
Outside the VirtualHost *:443, add this configuration:
<VirtualHost *:80>
ServerName git.example.com
RewriteEngine on
RewriteCond %{SERVER_NAME} =git.example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
This will redirect anyone visiting the HTTP site to the HTTPS site.
HAProxy
Basic HTTP
To setup HAProxy on port 80, without a virtualhost, you can add the following stanza to your haproxy.cfg:
listen forgejo_80
bind :::80 v4v6
mode http
timeout connect 10s
timeout client 30s
timeout server 30s
server forgejo 127.0.0.1:3000
HTTPS
To setup basic HTTPS proxying with HAProxy, you can add these blocks to your haproxy configuration:
Redirection to SSL
listen forgejo_80
bind :::80 v4v6
mode http
timeout connect 10s
timeout client 30s
timeout server 30s
redirect scheme https code 301
SSL frontend
frontend forgejo_443
bind :::443 v4v6 ssl crt /etc/haproxy_certs/forgejo.example.org.pem
mode http
option httplog
option forwardfor
timeout client 1m
use_backend forgejo_443 if { ssl_fc_sni forgejo.example.org }
SSL backend
backend forgejo_443
mode http
timeout connect 10s
timeout server 30s
server forgejo 127.0.0.1:3000
HTTPS with UNIX Socket
A Unix socket has lower latency compared to TCP. When combined with HAProxy, it provides a highly responsive and excellent user interface experience.
We assume that:
- Redirection to SSL and the SSL frontend configuration remain unchanged from the TCP setup.
- you are running Forgejo as
gituser and HAProxy ashaproxyuser. - the chroot environment is set to the directory
/var/lib/haproxy. - you have included the following settings in the
serverstanza of Forgejo:
[server]
PROTOCOL = http+unix
HTTP_ADDR = /var/lib/haproxy/forgejo/forgejo.sock
UNIX_SOCKET_PERMISSION = 660
...
Now you need to create a directory which can be acceessed either by the chroot environment used by HAProxy, and by Forgejo.
install -o git -g haproxy -m 0770 -d /var/lib/haproxy/forgejo
Finally, you can add these blocks into your haproxy.cfg.
chroot
you include these lines in the global section of your haproxy configuration
global
chroot /var/lib/haproxy
user haproxy
group haproxy
...
SSL Backend
The backend configuration will be as follows:
backend forgejo_443
mode http
timeout connect 10s
timeout server 30s
server forgejo /forgejo/forgejo.sock tfo
note: The Unix socket path is relative to the path of the chroot environment
HAProxy with UNIX socket using Puppet
This configuration relies on Puppetlabs HAProxy module.
This code sample is a compromise for the sake of the conciseness.
The Forgejo backend will be available only at the second execution of Puppet, unless you add a statement to create a user in advance, and you don't need to set the dependency for the 2 directories against the HAProxy class. You also need to push the SSL certificate, but all this goes far beyond the scope of this documentation.
file {
default:
notify => Service['haproxy'],
require => [Class['haproxy'], User['git']];
'/etc/haproxy_certs':
ensure => directory,
purge => true,
mode => '0700',
owner => haproxy,
group => haproxy,
recurse => true;
'/var/lib/haproxy/forgejo':
ensure => directory,
mode => '0770',
owner => git,
group => haproxy;
}
class { 'haproxy':
package_ensure => $haproxy_version,
global_options => {
'log' => "/dev/log local0\n log /dev/log local1 notice",
'chroot' => '/var/lib/haproxy',
'maxconn' => '150000',
'user' => 'haproxy',
'group' => 'haproxy',
'stats' => 'socket /var/run/haproxy.sock user root group sensu mode 660 level admin',
'tune.ssl.default-dh-param' => '2048',
},
defaults_options => {
'default-server' => 'init-addr libc,none',
'log' => 'global',
'retries' => '5',
'option' => ['redispatch', 'http-server-close', 'logasap'],
'timeout' => ['http-request 7s', 'connect 5s', 'check 9s'],
'maxconn' => '5000',
};
}
haproxy::listen { 'forgejo_80':
bind => { ':::80' => ['v4v6'] },
mode => 'http',
options => [
{ 'timeout' => 'connect 10s' },
{ 'timeout' => 'client 1m' },
{ 'timeout' => 'server 1m' },
{ 'redirect' => 'scheme https code 301' },
];
}
haproxy::frontend { 'forgejo_socket':
bind => { ':::443' => ['v4v6', 'ssl', 'crt', '/etc/haproxy_certs/forgejo.example.com.pem'] },
options => [
{
mode => 'http',
option => ['httplog', 'forwardfor'],
},
{ 'timeout' => 'client 1m' },
{ 'use_backend' => "forgejo if { ssl_fc_sni forgejo.example.com }" },
];
}
haproxy::backend { 'forgejo_socket':
options => [
{ 'mode' => 'http' },
{ 'timeout' => 'connect 10s' },
{ 'timeout' => 'server 1m' },
{ 'server' => 'forgejo /forgejo/forgejo.sock tfo' },
];
}
Caddy
HTTPS
To set up basic HTTPS proxy in Caddy with Caddyfile create a file forgejo in /etc/caddy/conf.d and add the following configuration:
git.example.com {
reverse_proxy 127.0.0.1:3000
}
Caddy will automatically get certificates for the domain.
HTTPS with a subpath
If you want to serve Forgejo on a subpath, e.g. on https://example.com/code, use the following configuration:
example.com {
route /code/* {
uri strip_prefix /code
reverse_proxy 127.0.0.1:3000
}
}
Make sure to set the Forgejo ROOT_URL configuration key to the URL with the subpath, otherwise links generated by Forgejo will be broken.
Proxy Authentication
Forgejo supports Reverse Proxy Header authentication, it will read headers as a trusted login user name or user email address. This hasn't been enabled by default, you can enable it with
[service]
ENABLE_REVERSE_PROXY_AUTHENTICATION = true
The default login user name is in the X-WEBAUTH-USER header, you can change it via changing [security].REVERSE_PROXY_AUTHENTICATION_USER in app.ini. If the user doesn't exist, you can enable automatic registration with ENABLE_REVERSE_PROXY_AUTO_REGISTRATION=true.
The default login user email is X-WEBAUTH-EMAIL, you can change it via changing [security].REVERSE_PROXY_AUTHENTICATION_EMAIL in app.ini, this could also be disabled with ENABLE_REVERSE_PROXY_EMAIL
If set ENABLE_REVERSE_PROXY_FULL_NAME=true, a user full name expected in X-WEBAUTH-FULLNAME will be assigned to the user when auto creating the user. You can also change the header name with [security].REVERSE_PROXY_AUTHENTICATION_FULL_NAME.
You can also limit the reverse proxy's IP address range with [security].REVERSE_PROXY_TRUSTED_PROXIES which default value is 127.0.0.0/8,::1/128. By [security].REVERSE_PROXY_LIMIT, you can limit trusted proxies level.
Notice: Reverse Proxy Auth doesn't support the API. You still need an access token or basic auth to make API requests.
Docker / Container Registry
The container registry uses a fixed sub-path /v2 which can't be changed.
Even if you deploy Forgejo with a different sub-path, /v2 will be used by the docker client.
Therefore you may need to add an additional route to your reverse proxy configuration.
Storage settings
The storage for each subsystem is defined in app.ini. It can either
be on disk (local which is the default) or using a S3 compatible
server (minio). In both cases each subsystem stores all files (or
objects in the S3 parlance) in a dedicated directory as shown in the
table below:
| subsystem | directory | app.ini sections |
|---|---|---|
| Attachments | attachments/ | [attachment] |
| LFS | lfs/ | [lfs] |
| Avatars | avatars/ | [avatar] |
| Repository avatars | repo-avatars/ | [repo-avatar] |
| Repository archives | repo-archive/ | [repo-archive] |
| Packages | packages/ | [packages] |
| Actions logs | actions_log/ | [storage.actions_log] |
| Actions Artifacts | actions_artifacts/ | [actions.artifacts] |
For instance:
- if the
STORAGE_TYPEislocalandAPP_DATA_PATHis/appdata, the default directory to store attachments is/appdata/attachments - if the
STORAGE_TYPEisminio, the default directory to store attachments within theMINIO_BUCKETbucket will beattachments/.
Changing the storage for all subsystems
The [storage] section can be used to modify the storage of all
subsystems. The default is to use local storage under
APP_DATA_PATH and is equivalent to writing the following in app.ini:
[server]
APP_DATA_PATH = /forgejo/data
[storage]
STORAGE_TYPE = local
PATH = /forgejo/data
Using local
For local storage, the [storage] section can only be used to
change the path under which all subsystems directories will be
created, using the PATH settings with an absolute pathname.
For instance:
[storage]
STORAGE_TYPE = local
PATH = /mystorage
will change the default for storing attachments to
/mystorage/attachments, LFS to /mystorage/lfs etc.
Using minio
The [storage] section can be used to change the default storage type
used by all subsystems to minio.
For instance:
[storage]
STORAGE_TYPE = minio
MINIO_ENDPOINT = 127.0.0.1:9000
MINIO_ACCESS_KEY_ID = [redacted]
MINIO_SECRET_ACCESS_KEY = [redacted]
MINIO_BUCKET = forgejo
MINIO_LOCATION = us-east-1
will change the default for storing attachments to attachments/ in
the forgejo bucket, LFS to lfs/ in the forgejo bucket etc.
[!note] Note
MINIO_BASE_PATHmust not be set in the[storage]section.
The configuration option MINIO_USE_SSL defaults to false to maintain compatibility with locally hosted MinIO instances. If an external S3 provider is intended to be used, this option should be set to true.
For instance, assuming a MinIO instance at https://minio.example.com:
[storage]
STORAGE_TYPE = minio
MINIO_USE_SSL = true
MINIO_ENDPOINT = minio.example.com
MINIO_ACCESS_KEY_ID = [redacted]
MINIO_SECRET_ACCESS_KEY = [redacted]
MINIO_BUCKET = bucket
MINIO_LOCATION = us-east-1
Storage settings for a single subsystem
It is possible to configure some subsystems to use S3 storage and others to use local storage by adding settings to their respective sections. For instance:
[attachment]
PATH = /otherstorage/attachments
[lfs]
STORAGE_TYPE = minio
MINIO_BASE_PATH = lfs/
MINIO_ENDPOINT = 127.0.0.1:9000
MINIO_ACCESS_KEY_ID = [redacted]
MINIO_SECRET_ACCESS_KEY = [redacted]
MINIO_BUCKET = forgejo
MINIO_LOCATION = us-east-1
will store attachments in the local directory
/otherstorage/attachments while lfs files will be stored in the S3
server within the lfs/ directory of the forgejo bucket.
Storage settings
The value of STORAGE_TYPE can be local (the default) for file
system directories or minio for S3 servers. Each storage type has
its own settings, as explained below.
Using local
There is just one setting when the STORAGE_TYPE is set to local:
PATH. It must be an absolute path and is interpreted as follows.
In the [storage] section, PATH is the path under which the
directories of each subsystem will be created instead of
APP_DATA_PATH. For instance, if APP_DATA_PATH equals /appdata
[storage]
STORAGE_TYPE = local
PATH = /mystorage
will create attachments in /mystorage/attachments instead of
/appdata/attachments, LFS files in /mystorage/lfs instead of
/appdata/lfs, etc.
In the section dedicated to a subsystem (see the table in the introduction), PATH
is the base path under which all files will be stored. For instance:
[storage]
STORAGE_TYPE = local
PATH = /mystorage
[attachment]
STORAGE_TYPE = local
PATH = /otherstorage/attachments
will store attachments in /otherstorage/attachments while lfs
files will be stored in /mystorage/lfs.
Using minio
When the STORAGE_TYPE is set to minio, the settings are used to to
connect to a S3 compatible server:
SERVE_DIRECT: false: Allows the storage driver to redirect to authenticated URLs to serve files directly. Only supported via signed URLs.MINIO_ENDPOINT: localhost:9000: S3 endpoint to connect.MINIO_ACCESS_KEY_ID: S3 accessKeyID to connect.MINIO_SECRET_ACCESS_KEY: S3 secretAccessKey to connect.MINIO_BUCKET: forgejo: S3 bucket to store the data.MINIO_BUCKET_LOOKUP: auto: S3 bucket lookup type.autoAuto detecteddnsVirtual Host stylepathPath Style
MINIO_LOCATION: us-east-1: S3 location to create bucket.MINIO_USE_SSL: false: S3 enabled ssl.MINIO_INSECURE_SKIP_VERIFY: false: S3 skip SSL verification.MINIO_CHECKSUM_ALGORITHM: Minio checksum algorithm: default (for MinIO, garage or AWS S3) or md5 (for Cloudflare or Backblaze).
When used in the [storage] section they apply to all
subsystems. When used in the section specific to a subsystem (see the table in the introduction), they
are only used for objects that belong to this subsystem. Here is a example:
[storage]
STORAGE_TYPE = minio
SERVE_DIRECT = false
MINIO_ENDPOINT = garage:9000
MINIO_ACCESS_KEY_ID = [redacted]
MINIO_SECRET_ACCESS_KEY = [redacted]
MINIO_BUCKET = forgejo
MINIO_BUCKET_LOOKUP = auto
MINIO_LOCATION = us-east-1
MINIO_USE_SSL = false
MINIO_INSECURE_SKIP_VERIFY = false
MINIO_CHECKSUM_ALGORITHM = md5
[lfs]
STORAGE_TYPE = minio
MINIO_BASE_PATH = nonstandardlfs/
SERVE_DIRECT = false
MINIO_ENDPOINT = minio:9000
MINIO_ACCESS_KEY_ID = [redacted]
MINIO_SECRET_ACCESS_KEY = [redacted]
MINIO_BUCKET = forgejo
MINIO_BUCKET_LOOKUP = auto
MINIO_LOCATION = us-east-1
MINIO_USE_SSL = false
MINIO_INSECURE_SKIP_VERIFY = false
MINIO_BASE_PATH: only valid in the specific subsystem section (see the table in the introduction) overrides the default directory in which objects are stored in theMINIO_BUCKETbucket.
For all subsystems that use the minio storage type found in the
[storage] section, the directory in which the objects are stored is
determined using the table in the introduction. For instance LFS files will be
stored in the lfs/ directory within the forgejo bucket.
When the minio storage is set in a section specific to a subsystem,
the MINIO_BASE_PATH setting can be used to override the default
directory. In the example above, MINIO_BASE_PATH = nonstandardlfs/
means LFS objects will be stored in the nonstandardlfs/ directory
within the forgejo bucket instead of the lfs/ directory
S3 servers compatibility
Although the S3 storage type is named minio it does not rely on any
MinIO specific features. The S3 storage type is
tested to be compatible with:
Undocumented features
It is strongly recommended to avoid using undocumented features -
such as [storage.attachments] as an alternative to [attachment]
for instance (the plural is not a typo, it is a unification problem) -
because their behavior is not thoroughly tested and may lead to
unexpected results.
Legacy settings
Some settings are deprecated but still supported in the interest of backward compatibility. They should be replaced as follows:
[server].LFS_CONTENT_PATHis replaced with[lfs].PATH[picture].AVATAR_UPLOAD_PATHis replaced with[avatar].PATH[picture].REPOSITORY_AVATAR_UPLOAD_PATHis replaced with[repo-avatar].PATH
Legacy settings have a lower priority and will be overridden by their replacement if both are present. For instance:
[picture]
AVATAR_UPLOAD_PATH = /legacy_path
[avatar]
PATH = /avatar_path
will store avatar files in /avatar_path.
Recommended Settings and Tips
The default settings are applicable to a broad range of Forgejo instances. Nevertheless, not every instance has the same purpose and number of users. This document lists settings suggested for various situations, the results of such configuration changes, and their use cases.
Recommended Settings
In this document, configuration parameters are described as [section.part].ENABLE_FEATURE_XY, with section and .part indicating the section and subsection accordingly, and ENABLE_FEATURE_XY reflecting the key. As an example, here's how it would look like in the app.ini file:
[section.part]
ENABLE_FEATURE_XY = new_value
Please bear in mind that you don't have to create new sections for every value; you can have multiple settings in the same section, such as:
[section.part]
ENABLE_FEATURE_XY = new_value
DISABLE_FEATURE_Z = other_new_value
The recommended settings are sorted alphabetically rather than by importance.
[database].DB_TYPE
For every action, operation or page you visit, Forgejo must query a database for data. The database is an important part of the Forgejo stack and therefore must be configured with care to ensure proper operation. However, it is difficult to give a recommendation due to its general nature and the many factors that affect the use of the database. So keep the following text in mind when configuring and choosing the database and always test carefully if the configuration suits your situation and ask for assistance if needed.
If your instance sees a low to moderate amount of activity, it is recommended to change this value to sqlite3. SQLite3 is a simple, non-maintenance requirement and one file on disk database. It is by far the easiest database to configure and has many other advantages over the other databases, but it becomes a poor choice once you see a lot of concurrent activity in which case performance may decrease, but SQLite can go a long way in the early years of an instance.
If your instances see a high amount of activity, it is recommended to change this value to mysql or postgres. There is no best managed database server, and it mainly depends on your previous experience and knowledge about the database you want to use, both can handle large amounts of activity, please refer to the database-configuration about what other values should be configured to connect to the database server.
[!warning] Warning Keep in mind that transitioning to another database with an existing database is not a trivial task and must be done carefully.
[cache].ADAPTER
Forgejo uses caching to avoid repeating expensive operations. The default cache implementation is basic: items expire after a fixed duration (time-to-live) regardless of usage frequency, and it lacks eviction strategies based on memory pressure or access patterns (like LRU). This simplicity means it may not be optimal for all workloads. To illustrate the potential impact of caching, consider these common use cases:
- Calculating commit counts for repositories or branches (reducing potentially expensive Git operations).
- Retrieving specific file or commit history (reducing Git I/O).
- Fetching user settings (minimizing database lookups).
- Computing avatar hashes (saving CPU time).
If your instance does not see much activity, it is recommended to change this value to twoqueue. This will use a size-limited LRU cache, which will keep frequently used items and remove the ones that are not used often. It is also recommended to change [cache].HOST to {"size":100, "recent_ratio":0.25, "ghost_ratio":0.5} because the default value has a limit of 50,000 items and since by default it will keep items for 16 hours, it is not memory efficient to possibly keep so many items for a small instance.
If your instance sees a lot of activity, it is recommended to change this value to redis or memcache. In that case, caching is outsourced to third-party software designed to cache items. Keep in mind that you will probably also need to modify [cache].HOST to configure the use of this software.
The redis adapter should support most software that works with a limited subset of the Redis Go Client APIs. In particular, Forgejo has integration tests against:
- Redis v7.2; higher versions will not be officially supported due to licensing concerns,
- Redict, a fork of Redis v7.2 licensed under the Lesser GNU General Public license (
LGPL-3.0-only), - Valkey, a fork of Redis v7.2 stewarded by the Linux Foundation, and
- Garnet, an independently implemented cache-store using Redis's RESP.
[repository.signing].DEFAULT_TRUST_MODEL
When Forgejo needs to verify a GPG or SSH signed commit on a repository, it checks who it can trust to have a verified commit on that repository. The default value for this setting is that Forgejo trusts only contributors to that repository to have signed commits, this can cause unexpected behavior for those used to GitHub when hosting repositories that anyone can contribute to, because non-collaborators with signed commits on that repository are shown as unverified.
If your instance expects users to contribute to other repositories within your instance, it is recommended that you change this value to committer. In that case, signed commits will appear as verified even if they are not collaborators.
[security].LOGIN_REMEMBER_DAYS
When a user logs in with the remember option enabled, they receive a long-term authentication cookie that is remembered for a number of days, determined by this setting. The default value is one month, which may be less than other services and could be frustrating for the user to log in every month.
If your instance does not need to adhere to a security policy that mandates a different value, it is recommended that you change this value to 365. In that case, the long-term authentication cookie will be stored on the user's device for one year.
[service].ENABLE_CAPTCHA
In recent years, spam bots have gotten smarter and have automated more than ever. A simple register form such as in Forgejo is a simple task for bots to register a new user and comment wherever they can about their favorite scam website. Forgejo provides the option to enable captcha on the register form.
If your instance has an open registration, it is recommended to change this value to true. You also need to choose which captcha you want to use, you can find more about that in the service configuration. Keep in mind that certain types of captcha limit the accessibility of registering new users because they often use images that are difficult to see.
[ui].ONLY_SHOW_RELEVANT_REPOS
The explore page is a good way to quickly check what is happening with an instance because it shows the most recent repositories on which action has been taken. If your instance sees a lot of activity, such as with a large user base, this explore page can quickly become a cluttered place where most of the repositories may not be relevant, such as a test repository or someone's personal dotconfig repository, which does not necessarily add to the effect of seeing what is happening on that instance.
If you have an instance with a lot of activity, it is recommended to change this value to true. In that situation, the explore page will filter out repositories that are likely to be less relevant in order to see what interesting projects are available on that instance.
[service].USERNAME_COOLDOWN_PERIOD
If a user or an organization is renamed, each old username, until it is claimed, will redirect to the latest username. In the context of public forges, to prevent namesquatting and allow users to reverse their username change within a certain period of time, a cooldown period can be configured to ensure that no user can claim the username within the cooldown period (with the exception of the original user and administrators).
If your instance has an open registration, it is recommended to change this value to 7. This means that there is a seven-day cooldown period for old usernames before they can be claimed by anyone, and that users can revert to their old username within seven days.
There is a closely related configuration option [service].MAX_USER_REDIRECTS for which the default value is 5 when a cooldown period is specified. This controls the number of user redirects a user can have (and therefore how many usernames are subject to a cooldown period). The intention of this option is to prevent abuse of the cooldown feature by limiting the amount of usernames that one user can keep on cooldown.
OpenSSH recommendations
This section only applies if you've enabled SSH (enabled by default), and are using sshd provided by OpenSSH on the host. Using OpenSSH is Forgejo's recommended practice. Forgejo also provides a built-in SSH server ([ssh].START_SSH_SERVER set to true) where these OpenSSH recommendations would not be applicable.
We recommend that you scope these settings in the sshd_config for the git user (or another user if it's set differently in [ssh].SSH_USER). All the recommendations below match on the git user.
Git's wire protocol v2
Git will tell the server over SSH that it is able to use a newer version of the Git Wire Protocol, but by default, SSH servers like OpenSSH will not pass the environment to Forgejo.
You have to tell the SSH server to pass the GIT_PROTOCOL environment, which can be configured as follows:
Match User git
AcceptEnv GIT_PROTOCOL
Per source penalty
This only applies if you reverse proxy SSH connections, and thus sshd do not get the original client IP.
Since OpenSSH 9.8, sshd will penalize sources (IP addresses) if they do something other than authenticating correctly. Thus, in the case that sshd only ever sees the IP address of your proxy software, then after enough penalties it will block all incoming SSH connections. This is undesirable as legitimate users are now penalized by the bad behavior of malicious users, as such we recommend to disable the feature altogether as follows:
Match User git
PerSourcePenalties no
If you still want to have this feature while using a reverse proxy, you have two options. sshd doesn't support the PROXY protocol, so you either you have to use mmproxy[^1] or transparent proxying if your proxy software supports that. Both require changes in the firewall setup and transparent proxy additionally requires kernel parameters changes, which might be undesirable for your use case.
[^1]: Cloudflare introduced the concept of mmproxy, but we recommend go-mmproxy and mmproxy-rs as implementation over the implementation by Cloudflare.
AuthorizedKeys command
This is mostly applicable if you administer a Forgejo instance for many users, as this solves a scaling problem.
The default configuration is to create a authorized_keys file in the git user's .ssh directory, which contains all public SSH keys that users have uploaded to their account.
sshd reads the entire file[^2] when verifying if the public key is accepted, this in turn can lead to many read syscalls if the authorized_keys file is of a large size.
[^2]: Yes, it really consumes the whole file. https://github.com/openssh/openssh-portable/blob/f44f124a234785b9d2cd59a6da28737fb3c4ad9a/auth2-pubkeyfile.c#L433-L435
Forgejo can provide the authorized keys on-demand to sshd, by configuring AuthorizedKeysCommand.
If you compile forgejo from source, it should be noted that sshd requires the binary to be owned by root and not not writable by groups and others.
Furthermore you must specify the full path to the forgejo binary.
Match User git
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /usr/bin/forgejo --config /etc/forgejo/conf/app.ini keys -u %u -t %t -k %k
As of writing, you will run into another scaling problem. The whole config is parsed on each execution, depending on your config this might take a few seconds.
Tips
Database performance
When trying to understand poor database performance in conjunction with Forgejo, it is useful to set [database].SLOW_QUERY_THRESHOLD to a value lower than the default (5 seconds). This ensures that SQL queries that are slow, but not too slow to meet the default value, are logged and can provide insight into what kind of SQL queries are slow, moreover, this is useful information for Forgejo contributors to find the code where this SQL query is executed and understand the context.
Authentication
LDAP (Lightweight Directory Access Protocol)
Both the LDAP via BindDN and the simple auth LDAP share the following fields:
LDAP via BindDN
Adds the following fields:
-
Bind DN (optional)
- The DN to bind to the LDAP server with when searching for the user. This may be left blank to perform an anonymous search.
- Example:
cn=Search,dc=example,dc=com
-
Bind Password (optional)
- The password for the Bind DN specified above, if any. Note: The password is stored encrypted with the SECRET_KEY on the server. It is still recommended to ensure that the Bind DN has as few privileges as possible.
-
User Search Base (required)
- The LDAP base at which user accounts will be searched for.
- Example:
ou=Users,dc=example,dc=com
-
User Filter (required)
- An LDAP filter declaring how to find the user record that is attempting to
authenticate. The
%[1]smatching parameter will be substituted with the login name given on the sign-in form. - Example:
(&(objectClass=posixAccount)(|(uid=%[1]s)(mail=%[1]s))) - Example for Microsoft Active Directory (AD):
(&(objectCategory=Person)(memberOf=CN=user-group,OU=example,DC=example,DC=org)(sAMAccountName=%s)(!(UserAccountControl:1.2.840.113556.1.4.803:=2))) - To substitute more than once,
%[1]sshould be used instead, e.g., when matching the supplied login name against multiple attributes such as a user identifier, email, or even phone number. - Example:
(&(objectClass=Person)(|(uid=%[1]s)(mail=%[1]s)(mobile=%[1]s)))
- An LDAP filter declaring how to find the user record that is attempting to
authenticate. The
-
Enable user synchronization
- This option enables a periodic task that synchronizes the Forgejo users with
the LDAP server. The default period is every 24 hours, but that can be
changed in the app.ini file. See the
[cron.sync_external_users]section in the sample app.ini for detailed comments about that section. The User Search Base and User Filter settings described above will limit which users can use Forgejo and which users will be synchronized. When initially run, the task will create all LDAP users that match the given settings, so take care if working with large Enterprise LDAP directories.
- This option enables a periodic task that synchronizes the Forgejo users with
the LDAP server. The default period is every 24 hours, but that can be
changed in the app.ini file. See the
LDAP using simple auth
Adds the following fields:
-
User DN (required)
- A template to use as the user's DN. The
%smatching parameter will be substituted with the login name given on the sign-in form. - Example:
cn=%s,ou=Users,dc=example,dc=com - Example:
uid=%s,ou=Users,dc=example,dc=com
- A template to use as the user's DN. The
-
User Search Base (optional)
- The LDAP base at which user accounts will be searched for.
- Example:
ou=Users,dc=example,dc=com
-
User Filter (required)
- An LDAP filter declaring when a user should be allowed to log in. The
%smatching parameter will be substituted with the login name given on the sign-in form. - Example:
(&(objectClass=posixAccount)(|(cn=%[1]s)(mail=%[1]s))) - Example:
(&(objectClass=posixAccount)(|(uid=%[1]s)(mail=%[1]s)))
- An LDAP filter declaring when a user should be allowed to log in. The
Verify group membership in LDAP
Uses the following fields:
-
Group Search Base (optional)
- The LDAP DN used for groups.
- Example:
ou=group,dc=example,dc=com
-
Group Name Filter (optional)
- An LDAP filter declaring how to find valid groups in the above DN.
- Example:
(|(cn=forgejo_users)(cn=admins))
-
User Attribute in Group (optional)
- The user attribute that is used to reference a user in the group object.
- Example:
uidif the group object contains amember: benderand the user object contains auid: bender. - Example:
dnif the group object contains amember: uid=bender,ou=users,dc=planetexpress,dc=com.
-
Group Attribute for User (optional)
- The attribute of the group object that lists/contains the group members.
- Example:
memberUidormember
PAM (Pluggable Authentication Module)
This procedure enables PAM authentication. Users may still be added to the
system manually using the user administration. PAM provides a mechanism to
automatically add users to the current database by testing them against PAM
authentication. To work with normal Linux passwords, the user running Forgejo
must also have read access to /etc/shadow in order to check the validity of
the account when logging in using a public key.
Note: If a user has added SSH public keys into Forgejo, the use of these keys may bypass the login check system. Therefore, if you wish to disable a user who authenticates with PAM, you should also manually disable the account in Forgejo using the built-in user manager.
- Configure and prepare the installation.
- It is recommended that you create an administrative user.
- Deselecting automatic sign-up may also be desired.
- Once the database has been initialized, log in as the newly created administrative user.
- Navigate to the user settings (icon in the top-right corner), and select
Site Administration->Authentication Sources, and selectAdd Authentication Source. - Fill out the fields as follows:
Authentication Type:PAMName: Any value should be valid here; use "System Authentication" if you'd like.PAM Service Name: Select the appropriate file listed under/etc/pam.d/that performs the authentication desired.[^1]PAM Email Domain: The e-mail suffix to append to user authentication. For example, if the login system expects a user calledgituser, and this field is set tomail.com, then Forgejo will expect theuser emailfield for an authenticated GIT instance to begituser@mail.com.[^2]
Note: PAM support is added via build-time flags (TAGS="pam" make build),
and the official binaries provided do not have this enabled. PAM requires that
the necessary libpam dynamic library be available and the necessary PAM
development headers be accessible to the compiler.
[^1]:
For example, using standard Linux log-in on Debian "Bullseye" use
common-session-noninteractive - this value may be valid for other flavors of
Debian including Ubuntu and Mint; consult your distribution's documentation.
[^2]:
This is a required field for PAM. Be aware: In the above example, the
user will log into the Forgejo web interface as gituser and not gituser@mail.com.
FreeIPA
-
In order to log in to Forgejo using FreeIPA credentials, a bind account needs to be created for Forgejo:
-
On the FreeIPA server, create a
forgejo.ldiffile, replacingdc=example,dc=comwith your DN, and provide an appropriately secure password:dn: uid=forgejo,cn=sysaccounts,cn=etc,dc=example,dc=com changetype: add objectclass: account objectclass: simplesecurityobject uid: forgejo userPassword: secure password passwordExpirationTime: 20380119031407Z nsIdleTimeout: 0 -
Import the LDIF (change localhost to an IPA server if needed). A prompt for the Directory Manager password will be presented:
ldapmodify -h localhost -p 389 -x -D \ "cn=Directory Manager" -W -f forgejo.ldif -
Add an IPA group for forgejo_users:
ipa group-add --desc="Forgejo Users" forgejo_users -
Note: For errors about IPA credentials, run
kinit adminand provide the domain admin account password. -
Log in to Forgejo as an Administrator and click on "Authentication" under the Admin Panel. Then click
Add New Sourceand fill in the details, changing all where appropriate.