How to Install a Private Gitea Server with Nginx Reverse Proxy on Debian 12

Estimated reading: 15 minutes 45 views

Gitea is a lightweight, self-hosted Git service written in Go that provides a complete source code management platform with minimal resource consumption. It includes repository management, branch protection, code review, issue tracking, and web-based wiki capabilities without the substantial memory footprint of heavier alternatives like GitLab.

In this guide, you will deploy a private, production-ready Gitea instance on Debian 12 Bookworm. You will install the official standalone Gitea binary, configure a dedicated system user and systemd service unit, store persistent data using an embedded SQLite database, and configure an Nginx reverse proxy to securely manage HTTP traffic on port 80.

By the end of this tutorial, your private Gitea server will be fully operational behind Nginx, accessible through a web browser, and ready for team collaboration and administrative project management.

Prerequisites

  • A clean Debian 12 (Bookworm) server instance with root shell access.
  • At least 2 GB of RAM and 10 GB of available disk storage for repositories and database state.
  • Basic familiarity with Linux shell commands, systemd unit management, and Nginx reverse proxy fundamentals.

Key concepts

Gitea Architecture and Persistence

Gitea is distributed as a single compiled Go binary that bundles the web frontend, Git protocol handlers, and core application logic. It stores bare Git repositories directly on disk in standard directory trees while persisting metadata, accounts, and issues inside a relational database such as SQLite, PostgreSQL, or MariaDB.

Nginx Reverse Proxy Role

Running Gitea directly on standard privileged ports (80 or 443) requires elevated permissions or capability grants. Placing Nginx in front of Gitea allows the application to bind safely to an unprivileged loopback address (127.0.0.1:3000), while Nginx handles client connections, large file buffering, static content delivery, and future TLS termination.

Systemd Isolation and Service Security

Running network-facing services under a dedicated, unprivileged system user (`git`) prevents unauthorized server compromise if an application vulnerability occurs. A dedicated systemd unit handles process lifecycle, automated recovery upon failure, and boot persistence.

1. Install System Packages and Dependencies

Update the Debian APT package index and install Git, cURL, SQLite3, and Nginx. Git is required by Gitea to execute repository operations on disk, SQLite3 provides local database utilities, and Nginx serves as the reverse proxy front-end.

First, refresh the available package information so the following installation uses the configured repositories.

apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y git curl sqlite3 nginx

2. Create Dedicated Git System User

Create an unprivileged system user and group named ‘git’. This account isolates the Gitea daemon from root privileges and serves as the owner for repository repositories and working files.

Create an unprivileged system user and group named ‘git’. This account isolates the Gitea daemon from root privileges and serves as the owner for repository repositories and working files. Run the following command, preserved exactly from the validated recording, and check its result before moving on.

adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/git git

3. Prepare Directory Structure and Permissions

Set up standard directory locations for Gitea application data, logs, indexers, and configuration files. Ensure that the ‘git’ user owns the data path, while /etc/gitea is restricted to administrative and group read access.

Create the directories required by the application. Existing directories are preserved where the command uses the -p option.

mkdir -p /var/lib/gitea/{custom,data,indexers,log}
mkdir -p /etc/gitea
chown -R git:git /var/lib/gitea
chmod -R 750 /var/lib/gitea
chown -R root:git /etc/gitea
chmod 770 /etc/gitea

4. Download and Install the Gitea Binary

Download the official precompiled Gitea executable for Linux x86_64, place it into /usr/local/bin, and make it executable. The binary contains all dependencies and compiled web assets required to run the application.

Send a request to the specified address and inspect its response as part of this step.

curl -fsSL -o /usr/local/bin/gitea https://dl.gitea.com/gitea/1.22.3/gitea-1.22.3-linux-amd64 || curl -fsSL -o /usr/local/bin/gitea https://github.com/go-gitea/gitea/releases/download/v1.22.3/gitea-1.22.3-linux-amd64
chmod +x /usr/local/bin/gitea

5. Configure Gitea Application Settings

Create the main Gitea configuration file at /etc/gitea/app.ini. This configuration sets the application to listen on 127.0.0.1:3000, establishes SQLite3 as the storage database, defines the reverse-proxy root URL, and locks the installation wizard to prevent unauthorized initialization.

Write the configuration content shown below into the target file. The complete multi-line input is one terminal action, not separate shell commands.

cat <<'EOF' > /etc/gitea/app.ini
APP_NAME = Gitea: Git with a cup of tea
RUN_USER = git
RUN_MODE = prod
WORK_PATH = /var/lib/gitea

[repository]
ROOT = /var/lib/gitea/data/gitea-repositories

[database]
DB_TYPE  = sqlite3
PATH     = /var/lib/gitea/data/gitea.db

[server]
APP_DATA_PATH    = /var/lib/gitea/data
DOMAIN           = localhost
SSH_DOMAIN       = localhost
HTTP_ADDR        = 127.0.0.1
HTTP_PORT        = 3000
ROOT_URL         = http://127.0.0.1/
DISABLE_SSH      = false
SSH_PORT         = 22
LFS_START_SERVER = true

[security]
INSTALL_LOCK   = true
SECRET_KEY     = d3b07384d113edec49eaa6238ad5ff00
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-ID5UkftDFfyQ1l5n9r_w1K2k3e4r5t6y7u8i9o0pA

[service]
DISABLE_REGISTRATION              = true
REQUIRE_SIGNIN_VIEW               = false
ENABLE_CAPTCHA                    = false

[mailer]
ENABLED = false
EOF

chown root:git /etc/gitea/app.ini
chmod 660 /etc/gitea/app.ini

6. Create Systemd Service and Start Gitea

Define a systemd service unit file at /etc/systemd/system/gitea.service to manage Gitea lifecycle under the ‘git’ user. Reload systemd, enable the service to start automatically on system boot, and start the daemon immediately.

Write the configuration content shown below into the target file. The complete multi-line input is one terminal action, not separate shell commands.

cat <<'EOF' > /etc/systemd/system/gitea.service
[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now gitea

7. Create Initial Administrator User

Provision an administrator account using Gitea’s built-in command-line management interface. This creates the user directly within the SQLite database without requiring external email verification or web onboarding.

Provision an administrator account using Gitea’s built-in command-line management interface. This creates the user directly within the SQLite database without requiring external email verification or web onboarding. Run the following command, preserved exactly from the validated recording, and check its result before moving on.

su - git -c "GITEA_WORK_DIR=/var/lib/gitea gitea --config /etc/gitea/app.ini admin user create --admin --username greencloud --password 'DisposablePassword123!' --email [email protected]"

8. Configure Nginx Reverse Proxy

Create an Nginx server configuration block that proxies incoming port 80 traffic to the internal Gitea daemon at http://127.0.0.1:3000. Remove the default Debian welcome site, link the new configuration, verify syntax, and reload Nginx.

Write the configuration content shown below into the target file. The complete multi-line input is one terminal action, not separate shell commands.

cat <<'EOF' > /etc/nginx/sites-available/gitea
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1: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;
    }
}
EOF

rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/gitea
nginx -t
systemctl restart nginx

Step 8 · Configure Nginx Reverse Proxy

9. Log In to the Gitea Administration Console

Navigate to the Gitea login interface served by Nginx on port 80. Enter the administrator credentials provisioned in the previous step and submit the form to authenticate.

Open http://YOUR_IP_ADDRESS/user/login in your browser.

Replace YOUR_IP_ADDRESS with your server IP, or YOUR_DOMAIN with a domain pointing to your server, as applicable. The video shows the actual lab address, which can differ from yours. Use HTTPS only if it has been configured.

  • Enter “greencloud” in the user name field.
  • Enter “DisposablePassword123!” in the password field.
  • Click Sign In.

Step 9 · Log In to the Gitea Administration Console

10. Review User Profile and Preference Settings

Access the user profile management area to inspect account preferences, public bio configurations, and localized display options.

Open http://YOUR_IP_ADDRESS/user/settings in your browser.

Replace YOUR_IP_ADDRESS with your server IP, or YOUR_DOMAIN with a domain pointing to your server, as applicable. The video shows the actual lab address, which can differ from yours. Use HTTPS only if it has been configured.

11. Inspect SSH and GPG Security Key Management

Open the SSH / GPG Keys management section. This panel allows registering developer public keys to authenticate Git CLI push and pull transactions securely.

Open http://YOUR_IP_ADDRESS/user/settings/keys in your browser.

Replace YOUR_IP_ADDRESS with your server IP, or YOUR_DOMAIN with a domain pointing to your server, as applicable. The video shows the actual lab address, which can differ from yours. Use HTTPS only if it has been configured.

12. Inspect Site Administration Dashboard

Navigate to the Site Administration dashboard available to instance administrators. Verify system status, application version metadata, and backend database metrics.

Open http://YOUR_IP_ADDRESS/admin in your browser.

Replace YOUR_IP_ADDRESS with your server IP, or YOUR_DOMAIN with a domain pointing to your server, as applicable. The video shows the actual lab address, which can differ from yours. Use HTTPS only if it has been configured.

Step 12 · Inspect Site Administration Dashboard

13. Create a New Sandbox Repository

Open the repository creation form, specify ‘demo-project’ as the repository name, and submit the creation request to initialize a live Git repository on disk.

Open http://YOUR_IP_ADDRESS/repo/create in your browser.

Replace YOUR_IP_ADDRESS with your server IP, or YOUR_DOMAIN with a domain pointing to your server, as applicable. The video shows the actual lab address, which can differ from yours. Use HTTPS only if it has been configured.

  • Enter “demo-project” in the repo name field.
  • Click Create Repository.

14. Verify Repository in the Instance Catalog

Navigate to the global Explore Repositories index to verify that the newly created project is indexed and discoverable across the instance.

Open http://YOUR_IP_ADDRESS/explore/repos in your browser.

Replace YOUR_IP_ADDRESS with your server IP, or YOUR_DOMAIN with a domain pointing to your server, as applicable. The video shows the actual lab address, which can differ from yours. Use HTTPS only if it has been configured.

Step 14 · Verify Repository in the Instance Catalog

How the final setup works

Incoming HTTP requests hit Nginx listening on port 80. Nginx terminates client connections and forwards requests over loopback (127.0.0.1:3000) to the Gitea daemon running under the dedicated ‘git’ system account. Gitea interacts directly with its SQLite database (/var/lib/gitea/data/gitea.db) and manages bare Git repositories under /var/lib/gitea/data/gitea-repositories.

Troubleshooting

Nginx returns an HTTP 502 Bad Gateway response when browsing the Gitea URL.

Likely cause: The Gitea daemon is either not running, stopped due to an initialization error, or not listening on 127.0.0.1:3000.

Fix: Run ‘systemctl status gitea’ and inspect recent logs using ‘journalctl -u gitea -n 50 –no-pager’ to locate configuration syntax or permission errors.

Git push operations fail with an HTTP 413 Request Entity Too Large error.

Likely cause: Nginx defaults to a 1MB maximum client request body size, which blocks medium and large Git commit pushes.

Fix: Ensure ‘client_max_body_size 100M;’ is included inside the Nginx server block configuration, then run ‘systemctl reload nginx’.

Gitea service fails to start with permissions errors on SQLite or repository storage.

Likely cause: Files or directories inside /var/lib/gitea were created as root rather than the git system user.

Fix: Restore ownership across all Gitea working directories using ‘chown -R git:git /var/lib/gitea’ and restart the service.

Useful commands

Check Gitea Service Status

systemctl status gitea --no-pager

View Live Gitea Daemon Logs

journalctl -u gitea -f

Restart Gitea Service

systemctl restart gitea

Test Nginx Configuration

nginx -t

Reload Nginx Proxy

systemctl reload nginx

List Gitea Users via CLI

su - git -c "GITEA_WORK_DIR=/var/lib/gitea gitea --config /etc/gitea/app.ini admin user list"

Display Gitea Version

/usr/local/bin/gitea --version

Conclusion

You have successfully installed and configured a private Gitea server behind an Nginx reverse proxy on Debian 12. Gitea is managed securely as an isolated systemd daemon running under an unprivileged user, persistent data is stored in SQLite and dedicated repository paths, and Nginx terminates incoming web traffic on standard HTTP port 80. You also verified administrative capabilities by logging into the web interface, reviewing system settings, and provisioning a new Git repository.

  • Installed Gitea standalone binary and configured systemd process management under an unprivileged ‘git’ account.
  • Persisted application data and initialized repository storage with SQLite3 in /var/lib/gitea.
  • Configured Nginx reverse proxy on port 80 with increased upload buffers for large Git pushes.
  • Validated administrator access, user settings, SSH key panels, and verified repository creation in the web dashboard.
Share this Doc

How to Install a Private Gitea Server with Nginx Reverse Proxy on Debian 12

Or copy link

CONTENTS