How to Install Gitea Code Hosting using Docker on Rocky Linux 8

Gitea is a self-hosted code hosting service similar to Github, Bitbucket, and Gitlab. It is written in Go language and can be installed on multiple operating systems, including Linux, macOS, Windows, and architectures like amd64, i386, ARM, and others. Being a lightweight application, it can be installed with minimal hardware requirements. It includes a repository file editor, OpenSSH server, issue tracking, pull requests, user management, notifications, built-in wiki, LFS support, Git hooks, and much more.

In this article, you will learn to install Gitea using Docker on a Rocky Linux 8 server.


  • A Server running Rocky Linux 8.5.

  • A non-root user with sudo privileges.

  • Disable SELinux.

  • Update everything.

    $ sudo dnf update
  • Install essential packages.

    $ sudo dnf install yum-utils nano curl
  • A fully qualified domain name(FQDN) pointing to the server like

Step 1 - Configure Firewall

The first step is to configure the firewall. Rocky Linux uses Firewalld Firewall. Check the firewall's status.

$ sudo firewall-cmd --state

The firewall works with different zones, and the public zone is the default one that we will use. List all the services and ports active on the firewall.

$ sudo firewall-cmd --permanent --list-services

It should show the following output.

cockpit dhcpv6-client ssh

Allow HTTP and HTTPS ports.

$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https

Open port 2221 for SSH.

$ sudo firewall-cmd --permanent --add-port=2221/tcp

List all the services being enabled by the firewall.

$ sudo firewall-cmd --permanent --list-all

You should see a similar output.

  target: default
  icmp-block-inversion: no
  services: cockpit dhcpv6-client http https ssh
  ports: 2221/tcp
  forward: no
  masquerade: no
  rich rules:

Reload the firewall to enable the changes.

$ sudo firewall-cmd --reload

Step 2 - Install Docker

Rocky Linux ships with an older version of Docker. To install the latest version, first, install the official Docker repository.

$ sudo yum-config-manager \
    --add-repo \

Install the latest version of Docker.

$ sudo dnf install docker-ce docker-ce-cli

Enable and run the Docker daemon.

$ sudo systemctl enable docker --now

Verify that it is running.

? docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2022-04-02 13:26:08 UTC; 2s ago
 Main PID: 21152 (dockerd)
    Tasks: 7
   Memory: 30.9M
   CGroup: /system.slice/docker.service
           ??21152 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

By default, Docker requires root privileges. If you want to avoid using sudo every time you run the docker command, add your username to the docker group.

$ sudo usermod -aG docker $(whoami)

You will need to log out of the server and back in as the same user to enable this change.

Step 3 - Install Docker Compose

Download the latest stable release of Docker Compose.

$ sudo curl -L "$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Apply executable permissions to the Docker Compose binary file.

$ sudo chmod +x /usr/local/bin/docker-compose

Test the installation.

$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

Install the Docker-compose Bash Completion script.

$ sudo curl \
    -L \
    -o /etc/bash_completion.d/docker-compose

Reload your profile settings to make the bash-completion work.

$ source ~/.bashrc

Step 4 - Configure and Install Gitea

Configure System Timezone

You can check your system's current timezone by the following command.

$ timedatectl
  Local time: Mon 2022-05-02 06:38:36 UTC
           Universal time: Mon 2022-05-02 06:38:36 UTC
                 RTC time: Mon 2022-05-02 06:38:36
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

You can see that the system is set to GMT or UTC timezone. If you live in an area with a different timezone or want to change it, use the following command to do that.

$ sudo timedatectl set-timezone Asia/Kolkata

Check the timezone again.

$ timedatectl
Local time: Mon 2022-05-02 12:09:23 IST
           Universal time: Mon 2022-05-02 06:39:23 UTC
                 RTC time: Mon 2022-05-02 06:39:22
                Time zone: Asia/Kolkata (IST, +0530)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

You can see that the timezone has been updated to IST, which is GMT+5:30.

Create Gitea Directories

Create the directory for Gitea.

$ mkdir ~/gitea-docker

Switch to the Gitea directory.

$ cd ~/gitea-docker

Create directories for storing Gitea data and PostgreSQL databases.

$ mkdir {gitea,postgres}

Configure Gitea Docker Compose File

Get the UID (User Identifier) and GID (Group Identifier) values for the currently logged-in user. The first command generates the UID, while the second one generates the GID. Copy both the values as they will be required to configure the Docker compose file.

$ echo $(id -u)
$ echo $(id -g)

Create and open the Docker Compose file for editing.

$ nano docker-compose.yml

Paste the following code in it. Paste the UID and GID values generated earlier.

version: "3"

    external: false

    image: gitea/gitea:1.16.6
    container_name: gitea
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=postgres
      - GITEA__database__HOST=db:5432
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=gitea
    restart: always
      - gitea
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - "3000:3000"
      - "2221:22"
      - db

    image: postgres:14
    restart: always
      - POSTGRES_USER=gitea
      - POSTGRES_DB=gitea
      - gitea
      - ./postgres:/var/lib/postgresql/data

Save the file by pressing Ctrl + X and entering Y when prompted.

The above Docker Compose file deploys two containers - one for Gitea and one for PostgreSQL. We have added a few environment variables to configure the database details. To connect the PostgreSQL database to the Gitea container, we have specified the host as the name of the PostgreSQL service in the file.

The port parameters "3000:3000" and "2221:22" specifies the port mapping where the left port denotes the host port and the right port denotes the container port. Gitea uses port 3000 for its web service, which is what we have exposed to the server too. For SSH, our system is already using port 22 for logging purposes. Therefore, we specify a custom port to perform SSH operations. In our case, we are using port 2221. This port also needs to be opened via your firewall, which we already did in step 1 of this tutorial.

Both, Gitea and the PostgreSQL containers are connected via a common internal Docker network named gitea. The volume mounts will automatically create gitea and postgres directories in the current folder when you start your Docker installation. The user ID specified in the compose file is what the Gitea container will use to create the gitea directory. On the other hand, the PostgreSQL container will be managed by the user systemd-coredump which is the default behavior. You can change that behavior, but it is not necessary.

Customize your Gitea Installation

You can customize your Gitea installation by adding an app.ini file to the ~/gitea-docker/gitea/gitea/conf directory. After the installation, this file can be edited from inside the container from the /data/gitea/conf/app.ini location. You can use the sample ini file from Gitea's Github repository for reference.

Install Gitea

Run the following command to launch Gitea containers.

$ docker-compose up -d

Check the status of the containers to ensure they are running properly.

$ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED             STATUS             PORTS                                                                              NAMES
bd06e370c46b   gitea/gitea:1.16.6   "/usr/bin/entrypoint…"   19 minutes ago   Up 19 minutes>3000/tcp, :::3000->3000/tcp,>22/tcp, :::2221->22/tcp   gitea
3fc6c4bce810   postgres:14          "docker-entrypoint.s…"   19 minutes ago   Up 19 minutes   5432/tcp                                                                           gitea_db_1

You can also use the following command to check the status.

$ docker-compose ps
   Name                 Command               State                                       Ports
gitea        /usr/bin/entrypoint /bin/s ...   Up>22/tcp,:::2221->22/tcp,>3000/tcp,:::3000->3000/tcp
gitea_db_1 postgres    Up      5432/tcp

Step 5 - Install SSL

To install an SSL certificate using Let's Encrypt, we need to install the Certbot tool.

Firstly, you need to download and install the EPEL repository.

$ sudo dnf install epel-release

Run the following commands to install Certbot.

$ sudo dnf install certbot

Generate the SSL certificate.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d

The above command will download a certificate to the /etc/letsencrypt/live/ directory on your server.

Generate a Diffie-Hellman group certificate.

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Create a challenge web root directory for Let's Encrypt auto-renewal.

$ sudo mkdir -p /var/lib/letsencrypt

Create a Cron Job to renew the SSL. It will run every day to check the certificate and renew it if needed. For that, first, create the file /etc/cron.daily/certbot-renew and open it for editing.

$ sudo nano /etc/cron.daily/certbot-renew

Paste the following code.

certbot renew --cert-name --webroot -w /var/lib/letsencrypt/ --post-hook "systemctl reload nginx"

Save the file by pressing Ctrl + X and entering Y when prompted.

Change the permissions on the task file to make it executable.

$ sudo chmod +x /etc/cron.daily/certbot-renew

Step 6 - Install Nginx

We will be installing the latest version of Nginx. Create and open the file /etc/yum.repos.d/nginx.repo for editing.

$ sudo nano /etc/yum.repos.d/nginx.repo

Paste the following lines in it.

name=nginx stable repo

name=nginx mainline repo

Save the file by pressing Ctrl + X and entering Y when prompted.

Install Nginx.

$ sudo dnf install nginx

Verify the installation.

$ nginx -v
nginx version: nginx/1.20.2

Enable and start the Nginx service.

$ sudo systemctl enable nginx --now

Create and open the file /etc/nginx/conf.d/gitea.conf for editing.

$ sudo nano /etc/nginx/conf.d/gitea.conf

Paste the following code in it.

# Redirect all non-encrypted to encrypted
server {
    listen 80;
    listen [::]:80;
    return 301 https://$host$request_uri;

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate     /etc/letsencrypt/live/;
    ssl_certificate_key /etc/letsencrypt/live/;
    ssl_trusted_certificate /etc/letsencrypt/live/;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    access_log /var/log/nginx/ main;
    error_log  /var/log/nginx/;

    location / {
        client_max_body_size 100M;
        proxy_pass  http://localhost:3000;
        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;

Once finished, save the file by pressing Ctrl + X and entering Y when prompted. The above configuration allows Nginx to act as a proxy server and bind to the port 3000 on localhost. To enable the uploading of large files for Git LFS, you can change the value of the client_max_body_size variable as per requirement. For our tutorial, we are using 100 MB as the limit.

Open the file /etc/nginx/nginx.conf for editing.

$ sudo nano /etc/nginx/nginx.conf

Add the following line before the line include /etc/nginx/conf.d/*.conf;.

server_names_hash_bucket_size  64;

Save the file by pressing Ctrl + X and entering Y when prompted.

Verify the Nginx configuration file syntax.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Restart the Nginx service to enable the new configuration.

$ sudo systemctl restart nginx

Step 7 - Access and Set up Gitea

Visit the URL in your browser, and the following installation screen shall appear.

Gitea Installation Part 1

Most of the fields will be pre-filled for you based on the values from the Docker compose file.

Gitea Installation Part 2

Enter as the Server Domain and as the Gitea Base URL. Change the value for the SSH Server Port from 22 to 2221. Leave the remaining settings as it is.

If you want to use mail features, you can add your SMTP server details. Expand the Email Settings section of the page and enter values as shown in the screenshot. Make sure to include your SMTP port with the hostname as shown. For our tutorial, we are using the Amazon SES service. You can use any SMTP service of your choice.

Gitea Email Settings

There are a few more settings you should check out before installing. To change them, expand the Server and Third-Party Service Settings section of the page.

Gitea Server and Third-Party Service Settings

Change the settings as per your requirement. We have enabled the option Hide Email Addresses by Default to ensure greater privacy. If you don't want people to register an account, enable the Disable Self-Registration option.

Last but not the least, set up your administrator account. Expand the Administrator Account Settings section of the page and fill in the required values.

Gitea Administrator Account Settings

Click the Install Gitea button when finished to complete the installation. You will be redirected to the Gitea dashboard. If, for some reason, you get a 502 error, refresh the page.

Gitea Dashboard

Step 8 - Create First Repository

Let us create our first repository. To do that, click the + sign on the dashboard.

Gitea New Repository Button

Enter the repository details. Select the Default Issue label by choosing from the dropdown menu. Select an appropriate license for your repository.

Gitea New Repository Setup Page

Select the default branch for your repository.

Gitea New Repository Setup Page Part 2

Once satisfied, click the Create repository button to create your first repository on your Gitea installation. You will be redirected to your repository home.

Gitea Repository Page

Step 9 - Set up SSH

Let us set up SSH to use with our newly created repository.

For our tutorial, we will use a local PC with Ubuntu pre-installed. However, the commands should work on any OS terminal without much change.

Create a new SSH key to use with Gitea on your local PC.

$ ssh-keygen -f ~/.ssh/gitea-demo -t rsa -b 4096 -C "HowtoForge Gitea Demo" -q -N "yourpassphrase"

Enter a strong passphrase in place of the placeholder in the command above. This will create an SSH key at ~/.ssh/gitea-demo location.

Next, open your Gitea profile settings as shown by clicking the dropdown menu on your profile image and selecting the Settings option.

Gitea Profile Settings Button

Next, switch to the SSH/GPG Keys tab on the page.

Gitea SSH Key Page

Add a name for your SSH key. Go back to the terminal on your local PC and run the following command to output the public key for Gitea.

$ cat ~/.ssh/

Copy the resulting output and paste it back into the Content box on the SSH keys page of Gitea.

Click the Add Key button to finish adding the key.

Gitea SSH Keys List

Go back to your local PC and set up the SSH agent to remain active for 1 hour.

$ eval $(ssh-agent -t 3600)b

Add the newly created SSH key to the SSH agent.

$ ssh-add ~/.ssh/gitea-demo
Enter passphrase for /home/navjot/.ssh/gitea-demo:
Identity added: /home/navjot/.ssh/gitea-demo (HowtoForge Gitea Demo)

You will be prompted for your passphrase.

Step 10 - Clone Repository using SSH

Let us clone the newly created repository using SSH. Visit the repository page again and copy the SSH URL after selecting the SSH option.

Gitea Copy SSH URL

It should look like the following.

ssh://[email protected]:2221/navjot/howtoforge.git

Run the following command on your local PC to clone the repository using SSH.

$ git clone ssh://[email protected]:2221/navjot/howtoforge.git
Cloning into 'howtoforge'...
The authenticity of host '[]:2221 ([]:2221)' can't be established.
ECDSA key fingerprint is SHA256:sN0N4OkpChwuR00xpGZU1mGJrp7ktwHRC7uxGP7Nh08.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[]:2221,[]:2221' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (4/4), done.

You will be prompted to add the host credentials. Enter yes to proceed with cloning the repository.

You will see the cloned repository on your system.

$ ls

Switch to the directory.

$ cd howtoforge

Check the Git status of the newly cloned repository. For this, you should have Git installed on your local PC.

$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

This concludes that SSH is working perfectly.

Step 11 - Testing First Commit

Now that we have set up our first repository, it's time to make some changes and commit them back.

Let us update the file. On your local PC, open the readme file for editing.

$ nano

Edit the file and when finished, save it by pressing Ctrl + X and entering Y when prompted.

Check the Git status again.

$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)

no changes added to commit (use "git add" and/or "git commit -a")

This shows that the Readme file has been edited but not committed. Add the file to prepare it for commit.

$ git add

Commit the file.

$ git commit -m "Update the Readme file for Gitea tutorial."
[master 5e9b039] Update the Readme file for Gitea tutorial.
 1 file changed, 3 insertions(+), 1 deletion(-)

Push the file to your Gitea Server.

$ git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 392 bytes | 392.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: . Processing 1 references
remote: Processed 1 references in total
To ssh://
   a61dfce..5e9b039  master -> master

To confirm, go back to the Gitea repository page.

Gitea Successful Commit

You can notice that the Readme file has been updated, and the latest commit message is also shown. To view the changes, click on the commit message, and you can view the following page with differences.

Gitea Commit Details

This concludes our first commit for our repository. You can start working on your Gitea installation for your projects.

Step 12 - Upgrade Gitea

Upgrading Gitea is a simple process.

Shut down and remove the existing containers. Since the data is saved outside the containers on the host, it will be retained.

$ cd ~/gitea-docker
$ docker-compose down --remove-orphans

Open the docker-compose.yml file and change the version of the Gitea container. Next, pull the new Gitea image.

$ docker pull

Start the new containers.

$ docker-compose up -d

Check the status.

$ docker ps


This concludes our tutorial where we installed Gitea Code Hosting Service using Docker on a Rocky Linux server. We also installed the Nginx server to act as a proxy and exposed Gitea via a public URL using SSL. If you have any questions, post them in the comments below.

Share this page:

0 Comment(s)

Add comment

Please register in our forum first to comment.