apt install gnupg git curl jq
Gitea Server Setup
Install, configure and harden your own self-hosted git server with Gitea. Secure deployment with MySQL database, HTTPS, system integrated SSH server and backups.
- 1. Install required packages
- 2. MySQL/MariaDB Database configuration (Local or remote)
- 3. Download and verify Gitea
- 4. Create the git system user and directories
- 5. Install Gitea binary and bash-completion
- 6. Create and enable the systemd service
- 7. Generate self-signed certificate (recommended for LAN or reverse proxy, else use a CA signed certificate)
- 8. Adjust app.ini (auto-generated on first run)
- 9. Harden permissions
- 10. Gitea Upgrade script
- 11. Backup and restore
|
You should set up ufw, ssh and unattended-upgrades securely. These steps are almost identical on every Debian server setup, so they are omittede. |
Reference documentation: https://docs.gitea.com/installation/install-from-binary
1. Install required packages
2. MySQL/MariaDB Database configuration (Local or remote)
CREATE USER 'gitea'@'giteaserver' IDENTIFIED BY 'GITRS_MYSQL_PASSWORD';
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';
GRANT ALL PRIVILEGES ON giteadb.* TO 'gitea'@'giteaserver';
FLUSH PRIVILEGES;
3. Download and verify Gitea
export GITEA_VER=$(curl -s https://api.github.com/repos/go-gitea/gitea/releases/latest | grep '"tag_name":' | cut -d'"' -f4 | sed 's/^v//')
wget -O gitea https://dl.gitea.com/gitea/$(GITEA_VER)/gitea-$(GITEA_VER)-linux-amd64
wget -O gitea.asc https://dl.gitea.com/gitea/$(GITEA_VER)/gitea-$(GITEA_VER)-linux-amd64.asc
gpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2
gpg --verify gitea.asc gitea
chmod +x gitea
4. Create the git system user and directories
adduser \
--system \
--shell /bin/bash \
--gecos 'Git Version Control' \
--group \
--disabled-password \
--home /home/git \
git
mkdir -p /var/lib/gitea/{custom,data,log}
chown -R git:git /var/lib/gitea/
chmod -R 750 /var/lib/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea
5. Install Gitea binary and bash-completion
export GITEA_WORK_DIR=/var/lib/gitea/
cp gitea /usr/local/bin/gitea
wget -O gitea_bash_autocomplete https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/autocompletion/bash_autocomplete
cp gitea_bash_autocomplete /usr/share/bash-completion/completions/gitea
6. Create and enable the systemd service
wget -O gitea.service https://raw.githubusercontent.com/go-gitea/gitea/refs/heads/release/$(GITEA_VER)/contrib/systemd/gitea.service
cp gitea.service /etc/systemd/system/gitea.service
nano /etc/systemd/system/gitea.service
# Uncomment CapabilityBoundingSet=CAP_NET_BIND_SERVICE and AmbientCapabilities=CAP_NET_BIND_SERVICE to allow binding to ports <1024.
sudo systemctl enable gitea --now
7. Generate self-signed certificate (recommended for LAN or reverse proxy, else use a CA signed certificate)
cd /var/lib/gitea/custom/
gitea cert --host giteaserver --rsa-bits 4096
chown root:git *.pem
chmod 640 *.pem
cd ~
8. Adjust app.ini (auto-generated on first run)
Reference documentation: https://docs.gitea.com/next/administration/config-cheat-sheet This is just a template with the most interesting options, many variables should be already set, some of them with secret tokens that you should’t be modifying.
APP_NAME = My Gitea Server
RUN_USER = git
WORK_PATH = /var/lib/gitea
RUN_MODE = prod
[database]
DB_TYPE = mysql
HOST = dbserver:3306
NAME = giteadb
USER = gitea
PASSWD = GITEA_MYSQL_PASSWORD
SCHEMA =
SSL_MODE = skip-verify
PATH = /var/lib/gitea/data/gitea.db
LOG_SQL = false
[repository]
ROOT = /var/lib/gitea/data/gitea-repositories
[server]
SSH_DOMAIN = git.example.com
DOMAIN = git.example.com
ROOT_URL = https://git.example.com/
PROTOCOL = https
HTTP_PORT = 3000
SSH_PORT = 22
DISABLE_SSH = false
START_SSH_SERVER = false
SSL_MODE = self_signed
CERT_FILE = cert.pem
KEY_FILE = key.pem
APP_DATA_PATH = /var/lib/gitea/data
LANDING_PAGE = login
LFS_START_SERVER = true
LFS_ALLOW_PURE_SSH = true
LFS_JWT_SECRET = LFS_JWT_SECRET_HERE
OFFLINE_MODE = true
[lfs]
PATH = /var/lib/gitea/data/lfs
[mailer]
ENABLED = false
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = true
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = true
REQUIRE_SIGNIN_VIEW = true
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.localhost
[openid]
ENABLE_OPENID_SIGNIN = false
ENABLE_OPENID_SIGNUP = false
[cron.update_checker]
ENABLED = true
ENABLE_SUCCESS_NOTICE = true
SCHEDULE = @every 24h
[cron.gc_lfs]
ENABLED = false
RUN_AT_START = false
SCHEDULE = @every 72h
OLDER_THAN = 168h
LAST_UPDATED_MORE_THAN_AGO = 72h
NUMBER_TO_CHECK_PER_REPO = 0
PROPORTION_TO_CHECK_PER_REPO = 1
[session]
PROVIDER = file
[log]
MODE = console
LEVEL = info
ROOT_PATH = /var/lib/gitea/log
[repository.pull-request]
DEFAULT_MERGE_STYLE = merge
[repository.signing]
DEFAULT_TRUST_MODEL = committer
[security]
INSTALL_LOCK = true
INTERNAL_TOKEN = SECURITY_TOKEN_HERE
PASSWORD_HASH_ALGO = scrypt
[oauth2]
JWT_SECRET = OAUTH_JWT_SECRET_HERE
|
Gitea can share the same SSH port with the system sshd. Delete and re-add SSH keys in Gitea after enabling it. * Use your Debian user for regular system SSH. * Use the git user for Git SSH. |
9. Harden permissions
chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini
|
Gitea requires manual updating, I recommend downloading the official upgrade script and setting up a cron job with my update check script to get emailed for new versions. |
10. Gitea Upgrade script
wget -O giteaUpgrade.sh https://github.com/go-gitea/gitea/blob/main/contrib/upgrade.sh
chmod +x giteaUpgrade.sh
./giteaUpgrade.sh
10.1. Update-Notifier script
#!/bin/bash
set -euo pipefail
# Configuration
MAIL_TO="root@localhost"
GITEA_BINARY="/usr/local/bin/gitea"
VERSION_JSON_URL="https://dl.gitea.com/gitea/version.json"
CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-10}"
# Ensure required commands are available
for cmd in curl jq mail; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Error: '$cmd' is required but not installed." >&2
exit 1
fi
done
# Fetch latest version
latest=$(curl --connect-timeout "$CONNECT_TIMEOUT" -sL "$VERSION_JSON_URL" | jq -r .latest.version)
if [[ -z "$latest" ]]; then
echo "Error: Unable to determine the latest Gitea version." >&2
exit 1
fi
# Determine current installed version
current=$($GITEA_BINARY --version | awk '{print $3}')
if [[ -z "$current" ]]; then
echo "Error: Unable to determine the current Gitea version." >&2
exit 1
fi
# Compare versions and notify if an update is available
if [[ "$current" != "$latest" ]]; then
subject="Gitea update available: $current to $latest"
body="A new version of Gitea is available.\n\nCurrent installed version: $current\nLatest available version: $latest\n\nSee: https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md"
echo -e "$body" | mail -v -s "$subject" "$MAIL_TO"
echo "Notification sent to $MAIL_TO"
else
echo "Gitea is up to date (version $current)."
fi
11. Backup and restore
Reference documentation: https://docs.gitea.com/administration/backup-and-restore
11.1. Create a backup
gitea dump will create a zip file with all the data from your gitea installation, save it in a safe place.
su git -
gitea dump -c /etc/gitea/app.ini
11.2. Restore a backup
su git -
unzip gitea-dump.zip
cd gitea-dump
cp -R app.ini /etc/gitea/conf/app.ini
cp -R custom/* /var/lib/gitea/custom/
cp -R data/* /var/lib/gitea/data/
cp -R repos/* /var/lib/gitea/data/gitea-repositories/
chown -R git:git /etc/gitea/conf/app.ini /var/lib/gitea
rm -rf app.ini custom data repos
11.3. Reset a user password
gitea -c "/etc/gitea/conf/app.ini" admin change-password --username myusername --password newpassword