This guide provides step-by-step instructions to deploy a self-hosted Git server using Gitea on an Ubuntu machine. Gitea is a lightweight, open-source Git service that allows you to host private repositories, manage users and organizations, and integrate with CI/CD tools.
- An Ubuntu Server (LTS version recommended, e.g., 20.04, 22.04).
- A domain name (e.g.,
git.yourdomain.com
) pointing to your server's public IP address (DNS A record). sudo
privileges on the server.- Basic familiarity with the Linux command line.
First, ensure your Ubuntu system is up-to-date and install basic firewall rules.
# Update package lists and upgrade existing packages
sudo apt update && sudo apt upgrade -y
# Install Uncomplicated Firewall (UFW) if not already installed
sudo apt install ufw -y
# Allow essential ports: SSH (22), HTTP (80), HTTPS (443)
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
# Enable the firewall
sudo ufw enable
# Press 'y' and Enter when prompted
Install Git (required by Gitea), MariaDB (database server), Nginx (reverse proxy), and Certbot (for SSL certificates).
sudo apt install git mariadb-server nginx certbot python3-certbot-nginx -y
-
Secure MariaDB Installation: Run the security script to set a root password, remove anonymous users, disable remote root login, and remove the test database.
sudo mysql_secure_installation
- Answer 'Y' to set a strong root password.
- Answer 'Y' to remove anonymous users.
- Answer 'Y' to disallow root login remotely.
- Answer 'Y' to remove the test database.
- Answer 'Y' to reload privilege tables.
-
Create Gitea Database and User: Log in to MariaDB as the root user (using the password you just set).
sudo mysql -u root -p
Run the following SQL commands. Replace
<YOUR_STRONG_PASSWORD>
with a secure password for the Gitea database user.CREATE DATABASE gitea CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'; CREATE USER 'gitea'@'localhost' IDENTIFIED BY '<YOUR_STRONG_PASSWORD>'; GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost'; FLUSH PRIVILEGES; EXIT;
Keep this password safe; you will need it during the Gitea web setup.
-
Create Gitea System User: Create a dedicated system user for Gitea for security and isolation.
sudo useradd --system --shell /bin/bash --comment 'Git Version Control' --create-home --home /var/lib/gitea gitea
(Note: The previous command used
--home /var/lib/gitea
but didn't explicitly create it;--create-home
handles this.) -
Download Gitea Binary: Check the Gitea releases page for the latest version. Update the version number and download link accordingly.
# Example using version 1.23.4 - replace with the latest version if needed GITEA_VERSION="1.23.4" sudo wget -O /usr/local/bin/gitea https://dl.gitea.com/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64 sudo chmod +x /usr/local/bin/gitea # Verify the installation /usr/local/bin/gitea --version
-
Create Gitea Directories and Set Permissions: Create the necessary directory structure for Gitea's configuration, data, repositories, and logs.
sudo mkdir -p /etc/gitea /var/lib/gitea/{custom,data,log} sudo chown -R gitea:gitea /etc/gitea /var/lib/gitea/ sudo chmod -R 750 /var/lib/gitea/ sudo chmod 770 /etc/gitea # Give group write permission temporarily for web installer
Note: Permissions will be adjusted further after the initial web setup.
While much configuration happens via the web UI initially, setting key paths and domain info in app.ini
beforehand is recommended.
-
Create the Configuration File:
sudo touch /etc/gitea/app.ini sudo chown gitea:gitea /etc/gitea/app.ini sudo chmod 640 /etc/gitea/app.ini
-
Edit
app.ini
: Open the file for editing:sudo nano /etc/gitea/app.ini # Or: sudo vi /etc/gitea/app.ini
Paste the following content. Replace
<your_domain>
with your actual domain name (e.g.,git.yourdomain.com
).APP_NAME = Gitea Git Service RUN_USER = gitea RUN_MODE = prod [repository] ROOT = /var/lib/gitea/data/gitea-repositories [server] APP_DATA_PATH = /var/lib/gitea/data DOMAIN = <your_domain> SSH_DOMAIN = <your_domain> HTTP_PORT = 3000 ROOT_URL = https://<your_domain>/ DISABLE_SSH = false SSH_PORT = 22 LFS_START_SERVER = true LFS_CONTENT_PATH = /var/lib/gitea/data/lfs [database] DB_TYPE = mysql HOST = 127.0.0.1:3306 NAME = gitea USER = gitea PASSWD = '<YOUR_STRONG_PASSWORD>' # Use the password created in Step 3 CHARSET = utf8mb4 [service] REGISTER_EMAIL_CONFIRM = false ENABLE_NOTIFY_MAIL = false DISABLE_REGISTRATION = false # Set to 'true' after creating admin user if desired ENABLE_CAPTCHA = true REQUIRE_SIGNIN_VIEW = false [mailer] ENABLED = false [log] MODE = file LEVEL = Info ROOT_PATH = /var/lib/gitea/log [security] INSTALL_LOCK = false # Will become true after initial setup SECRET_KEY = # Leave blank - will be generated on first run
Save and close the file (Ctrl+X, then Y, then Enter in nano).
-
Adjust Permissions:
sudo chown root:gitea /etc/gitea/app.ini # Gitea needs to read it sudo chmod 640 /etc/gitea/app.ini
Create a systemd service file to manage the Gitea process (start, stop, restart, enable on boot).
-
Create the Service File:
sudo nano /etc/systemd/system/gitea.service
-
Add Service Configuration: Paste the following content:
[Unit] Description=Gitea (Git with a cup of tea) After=syslog.target After=network.target After=mariadb.service # Ensure MariaDB is running first [Service] # Modify these two values and uncomment them if you have # repos with lots of files and get an HTTP error 500 because # of that ### #LimitMEMLOCK=infinity #LimitNOFILE=65535 RestartSec=2s Type=simple User=gitea Group=gitea WorkingDirectory=/var/lib/gitea/ # Set environment variables for Gitea Environment=USER=gitea HOME=/var/lib/gitea GITEA_WORK_DIR=/var/lib/gitea ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini Restart=always # If using PAM uncomment below #ExecReload=/bin/kill -HUP $MAINPID # StandardOutput=syslog # StandardError=syslog # SyslogIdentifier=gitea [Install] WantedBy=multi-user.target
Save and close the file.
-
Enable and Start the Gitea Service:
sudo systemctl daemon-reload sudo systemctl enable --now gitea sudo systemctl status gitea # Check if it's active (running)
If it's not running, check the logs:
sudo journalctl -u gitea -f
Configure Nginx to act as a reverse proxy, forwarding external requests (HTTP/HTTPS) to the Gitea application running on port 3000.
-
Create Nginx Configuration File:
sudo nano /etc/nginx/sites-available/gitea
-
Add Nginx Configuration: Paste the following, replacing
<your_domain>
with your actual domain.server { listen 80; server_name <your_domain>; # Redirect HTTP to HTTPS (Certbot will likely handle this, but good practice) location / { return 301 https://$host$request_uri; } } server { listen 443 ssl http2; # Listen on port 443 for HTTPS server_name <your_domain>; # SSL Configuration (Certbot will add/modify these lines) # ssl_certificate /etc/letsencrypt/live/<your_domain>/fullchain.pem; # ssl_certificate_key /etc/letsencrypt/live/<your_domain>/privkey.pem; # include /etc/letsencrypt/options-ssl-nginx.conf; # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # Gitea proxy configuration location / { proxy_pass http://localhost:3000; # Forward requests to Gitea 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; # Consider increasing client_max_body_size if you plan large pushes/LFS client_max_body_size 100m; } # Add security headers (optional but recommended) add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; # add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';" always; # Adjust CSP as needed }
Save and close the file.
-
Enable the Nginx Site and Test Configuration:
sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/ sudo nginx -t # Test Nginx configuration for errors
If
nginx -t
shows "syntax is ok" and "test is successful", proceed. -
Restart Nginx:
sudo systemctl restart nginx
Use Certbot to obtain a free SSL certificate from Let's Encrypt and automatically configure Nginx for HTTPS.
-
Obtain the Certificate: Replace
<your_domain>
with your actual domain.sudo certbot --nginx -d <your_domain>
- Follow the prompts: Enter your email address, agree to the terms, and choose whether to share your email.
- Certbot will ask if you want to redirect HTTP traffic to HTTPS. Choose option 2 (Redirect).
-
Verify Auto-Renewal: Certbot typically sets up automatic renewal via a systemd timer or cron job. You can test it:
sudo certbot renew --dry-run
Now, access your Gitea instance in your web browser to complete the installation.
-
Navigate to Your Gitea URL: Open
https://<your_domain>
in your browser. You should see the Gitea initial configuration page. -
Configure Database Settings:
- Database Type: Select
MySQL
. - Host:
127.0.0.1:3306
- User:
gitea
- Password: Enter the
<YOUR_STRONG_PASSWORD>
you created in Step 3. - Database Name:
gitea
- Charset: Leave as
utf8mb4
.
- Database Type: Select
-
Configure General Settings:
- Site Title: Enter a name for your Gitea instance (e.g., "MyCompany Git").
- Repository Root Path: Ensure this matches
/var/lib/gitea/data/gitea-repositories
. - LFS Root Path: Ensure this matches
/var/lib/gitea/data/lfs
. - Run As Username: Ensure this is
gitea
. - SSH Server Domain: Ensure this is
<your_domain>
. - SSH Port: Ensure this is
22
(unless your SSH daemon runs on a different port and you've configured Gitea's internal SSH server accordingly). - Gitea Base URL: Ensure this is
https://<your_domain>/
. - Log Path: Ensure this is
/var/lib/gitea/log
.
-
Optional Settings (Configure as needed):
- Email Service Settings: Configure if you want email notifications.
- Server and Third-Party Service Settings: Configure integrations if needed.
-
Administrator Account Settings:
- IMPORTANT: Create your initial administrator account here. Choose a strong username and password. Enter your email address.
-
Click "Install Gitea" Wait for the installation process to complete. You should be redirected to the login page.
-
Log In: Log in using the administrator account credentials you just created.
-
(Security) Lock Down
app.ini
Further: After successful installation, theINSTALL_LOCK
setting in/etc/gitea/app.ini
should automatically be set totrue
. You can also tighten directory permissions now that the web installer is done:sudo chmod 750 /etc/gitea sudo chmod 640 /etc/gitea/app.ini
Gitea manages SSH access internally. Users need to add their public SSH keys to their Gitea account settings.
-
Generate an SSH Key (if you don't have one): On your local machine (not the server), run:
ssh-keygen -t ed25519 -C "[email protected]" # Or use RSA: ssh-keygen -t rsa -b 4096 -C "[email protected]"
Follow the prompts. Don't set a passphrase if you want seamless cloning, or use
ssh-agent
if you do. -
Copy Your Public Key: Display your public key (e.g.,
~/.ssh/id_ed25519.pub
or~/.ssh/id_rsa.pub
) and copy its content:cat ~/.ssh/id_ed25519.pub
-
Add Key to Gitea:
- Log in to your Gitea account on
https://<your_domain>
. - Go to
Settings
(usually under your profile picture). - Navigate to the
SSH / GPG Keys
tab. - Click
Add Key
. - Paste your entire public key (
ssh-ed25519 ...
orssh-rsa ...
) into theContent
box. - Give it a recognizable
Title
. - Click
Add Key
.
- Log in to your Gitea account on
-
Clone a Repository via SSH: Once you've created a repository (e.g.,
my-test-repo
) under your Gitea username (e.g.,admin
), you can clone it using the SSH URL provided by Gitea:# On your local machine git clone git@<your_domain>:<gitea_username>/<repository_name>.git # Example: git clone [email protected]:admin/my-test-repo.git
The first connection might ask you to confirm the host key fingerprint. Type
yes
.
Gitea includes a built-in CI/CD system called Gitea Actions, which is compatible with GitHub Actions syntax.
To enable and use it:
- Install Act Runner: You need to set up one or more "runners" that will execute the jobs defined in your workflow files (
.gitea/workflows/
). - Configure Gitea: Enable Gitea Actions in your
app.ini
or through the Gitea admin settings. - Register Runners: Link your runners to your Gitea instance.
Refer to the official Gitea Actions Documentation for detailed setup instructions, as it involves several configuration steps.
- Backups: Regularly back up:
- The Gitea database:
sudo mysqldump -u root -p gitea > gitea-db-backup-$(date +%F).sql
- The Gitea data directory:
sudo rsync -a /var/lib/gitea/ /path/to/your/backup/location/gitea-data/
(stop Gitea service first for consistency) - The Gitea configuration file:
/etc/gitea/app.ini
- The Gitea database:
- Updates: Periodically check for new Gitea releases. The update process typically involves:
- Stopping the Gitea service (
sudo systemctl stop gitea
). - Backing up your installation (see above).
- Downloading the new binary and replacing
/usr/local/bin/gitea
. - Starting the Gitea service (
sudo systemctl start gitea
). Gitea usually handles database migrations automatically on startup. Always consult the specific release notes for update instructions.
- Stopping the Gitea service (
- Logs: Check Gitea logs (
/var/lib/gitea/log/gitea.log
orsudo journalctl -u gitea
) and Nginx logs (/var/log/nginx/error.log
) for troubleshooting.