Installation with Docker

Forgejo provides container images for use with Docker or other containerization tools.

docker pull codeberg.org/forgejo/forgejo:15

If codeberg.org cannot be accessed, you can replace every mention of codeberg.org with data.forgejo.org to use our mirror.

The 15 tag is set to be the latest minor release, starting with 15.0.x. The 15 tag will then be equal to 15.0.4 when it is released and so on. The 15.0 tag is also set to be the latest patch version release.

Upgrading from X to X+1 (for instance from 12 to 13) requires a manual operation and human verification. However it is possible to use the X tag (for instance 13) to get the latest minor release automatically.

Security note for v15 LTS deployments

By default, the setting security.REVERSE_PROXY_TRUSTED_PROXIES is set to * in versions <16.0.0 of Forgejo container images. Paired with exposed web port and [service].ENABLE_REVERSE_PROXY_AUTHENTICATION set to true this can have devastating consequences to security.

The value * was changed in Forgejo v16.0.0, but as a breaking change it was not changed in v15 LTS.

To keep your deployment secure please make sure that:

  • When using reverse proxy, Forgejo web port (:3000 by default) is not directly accessible from untrusted networks
  • security.REVERSE_PROXY_TRUSTED_PROXIES is set to a some value other than *. For example, 127.0.0.0/8,::1/128. Additional networks can be added with commas, for example, to include your Docker bridge network

Docker:

Here is an example docker-compose file:

networks:
  forgejo:
    external: false

services:
  server:
    image: codeberg.org/forgejo/forgejo:15
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
    restart: always
    networks:
      - forgejo
    volumes:
      - ./forgejo:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - '3000:3000'
      - '222:22'

Note that the volume should be owned by the user/group with the UID/GID specified in the config file. If you don’t set the volume correct permissions, the container may not start.

Podman:

Currently tested on the following specifications:

  • Podman v5.2.1
  • Fedora 40, Alma Linux 9.4, Rocky Linux 9

Save the following files in /etc/containers/systemd, as port 222 requires elevated privileges:

# forgejo.container
[Container]
ContainerName=forgejo
Environment=USER_UID=1000
Environment=USER_GID=1000
Image=codeberg.org/forgejo/forgejo:15
Network=forgejo.network
PublishPort=3000:3000
PublishPort=222:22
Volume=forgejo-data:/data

[Service]
Restart=always

[Install]
WantedBy=default.target

---

# forgejo.network
[Network]
NetworkName=forgejo

---

#forgejo-data.volume
[Volume]
VolumeName=forgejo-data

Once saved, run:

sudo systemctl daemon-reload
sudo systemctl start forgejo

On a browser, go to http://localhost:3000 to initialize Onboarding

Note: SSH will be accessible to the container via port 222 on localhost. Once SSH keys have been verified on Forgejo, to confirm functionality, run:

ssh -F /dev/null git@<address> -p 222

Configuration

The Forgejo configuration is stored in the app.ini file as described in the Configuration Cheat Sheet. When using the Forgejo container image, this file is automatically created if it does not exist already.

It is possible to add and modify configuration values by setting environment variables named in format FORGEJO__[SECTION]__[KEY]. The DEFAULT section of the configuration should be an empty string. For instance:

FORGEJO____APP_NAME=Frogejo 🐸
FORGEJO__repository__ENABLE_PUSH_CREATE_USER=true

is equivalent to adding the following to app.ini:

APP_NAME=Frogejo 🐸

[repository]
ENABLE_PUSH_CREATE_USER = true
Note

It is not possible to use environment variables to remove an existing value, it must be done by editing the app.ini file.

Note

In case you are in a SELinux environment check the audit logs if you are having issues with containers.

Databases

In the following each database is shown as part of a docker-compose example file, with a diff-like presentation that highlights additions to the example above.

If no database is configured, it will default to using SQLite.

MySQL database

networks:
  forgejo:
    external: false

services:
  server:
    image: codeberg.org/forgejo/forgejo:15
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
+      - FORGEJO__database__DB_TYPE=mysql
+      - FORGEJO__database__HOST=db:3306
+      - FORGEJO__database__NAME=forgejo
+      - FORGEJO__database__USER=forgejo
+      - FORGEJO__database__PASSWD=forgejo
    restart: always
    networks:
      - forgejo
    volumes:
      - ./forgejo:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"
+    depends_on:
+      - db
+
+  db:
+    image: mysql:8
+    restart: always
+    environment:
+      - MYSQL_ROOT_PASSWORD=forgejo
+      - MYSQL_USER=forgejo
+      - MYSQL_PASSWORD=forgejo
+      - MYSQL_DATABASE=forgejo
+    networks:
+      - forgejo
+    volumes:
+      - ./mysql:/var/lib/mysql

PostgreSQL database

networks:
  forgejo:
    external: false

services:
  server:
    image: codeberg.org/forgejo/forgejo:15
    container_name: forgejo
    environment:
      - USER_UID=1000
      - USER_GID=1000
+      - FORGEJO__database__DB_TYPE=postgres
+      - FORGEJO__database__HOST=db:5432
+      - FORGEJO__database__NAME=forgejo
+      - FORGEJO__database__USER=forgejo
+      - FORGEJO__database__PASSWD=forgejo
    restart: always
    networks:
      - forgejo
    volumes:
      - ./forgejo:/data
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "222:22"
+    depends_on:
+      - db
+
+  db:
+    image: postgres:14
+    restart: always
+    environment:
+      - POSTGRES_USER=forgejo
+      - POSTGRES_PASSWORD=forgejo
+      - POSTGRES_DB=forgejo
+    networks:
+      - forgejo
+    volumes:
+      - ./postgres:/var/lib/postgresql/data

Using rootless image

Rootless image uses a different path for the data folder for Forgejo.

Also, the correct permissions must be set for bound folders, here, we will keep the user 1000 and groupid from before:

mkdir -p ./forgejo
sudo chown -R 1000:1000 ./forgejo

Here is an example of a docker-compose.yaml adapted from the previous PostgreSQL:

networks:
  forgejo:
    external: false

services:
  server:
-   image: codeberg.org/forgejo/forgejo:15
+   image: codeberg.org/forgejo/forgejo:15-rootless
    container_name: forgejo
+   user: 1000:1000
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - FORGEJO__database__DB_TYPE=postgres
      - FORGEJO__database__HOST=db:5432
      - FORGEJO__database__NAME=forgejo
      - FORGEJO__database__USER=forgejo
      - FORGEJO__database__PASSWD=forgejo
    restart: always
    networks:
      - forgejo
    volumes:
-      - ./forgejo:/data
+      - ./forgejo:/var/lib/gitea
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
-      - "222:22"
+      - "222:2222"
    depends_on:
      - db