Created
April 26, 2026 18:26
-
-
Save TheyCallMeLinux/ef1a46c5b3ab00bc1b8ab8a9885b253a to your computer and use it in GitHub Desktop.
Deploy Forgejo on Alma Linux 9 (mariadb)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| ############################ | |
| # VARIABLES | |
| ############################ | |
| DB_MODE="local" | |
| DB_HOST="127.0.0.1" | |
| DB_NAME="forgejo" | |
| DB_USER="forgejo" | |
| DB_PASS="CHANGEME" | |
| APP_URL="https://forgejo.example.com" | |
| SERVER_NAME="forgejo.example.com" | |
| HTTP_BIND="127.0.0.1" | |
| HTTP_PORT="3000" | |
| SSH_PORT="22" | |
| APP_NAME="example Forgejo" | |
| FORGEJO_VERSION="15.0.0" | |
| DISABLE_REGISTRATION="true" | |
| EMAIL_DOMAIN_ALLOWLIST="gmail.com" | |
| REQUIRE_SIGNIN_VIEW="true" | |
| EXTERNAL_REGISTRATION="true" | |
| REGISTER_EMAIL_CONFIRM="true" | |
| ENABLE_NOTIFY_MAIL="true" | |
| ENABLE_CAPTCHA="true" | |
| RUN_MODE="prod" | |
| SELINUX_MODE="permissive" | |
| SWAP_SIZE="4G" | |
| SWAPPINESS="10" | |
| CERT_COUNTRY="CA" | |
| CERT_STATE="ON" | |
| CERT_CITY="Toronto" | |
| CERT_ORG="exampleCorp" | |
| CERT_UNIT="IT" | |
| MAIL_ENABLED="true" | |
| SMTP_ADDR="smtp.gmail.com" | |
| SMTP_PORT="465" | |
| SMTP_USER="example@gmail.com" | |
| SMTP_PASS="APP PASS WORD" | |
| MAIL_FROM="example@gmail.com" | |
| SMTP_PROTOCOL="smtps" | |
| SSL_CERT="/etc/pki/tls/certs/forgejo.crt" | |
| SSL_KEY="/etc/pki/tls/private/forgejo.key" | |
| ############################ | |
| # LOGGING | |
| ############################ | |
| log() { | |
| echo "[DEPLOY] $1" | |
| } | |
| trap 'log "Deployment failed at line $LINENO"' ERR | |
| ############################ | |
| # SWAP + MEMORY TUNING | |
| ############################ | |
| if [ ! -f /swapfile ]; then | |
| log "Creating swap" | |
| fallocate -l ${SWAP_SIZE} /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=4096 | |
| chmod 600 /swapfile | |
| mkswap /swapfile | |
| swapon /swapfile | |
| echo '/swapfile none swap sw 0 0' >> /etc/fstab | |
| sysctl vm.swappiness=${SWAPPINESS} | |
| fi | |
| ############################ | |
| # SELINUX | |
| ############################ | |
| log "Configuring SELinux" | |
| case "$SELINUX_MODE" in | |
| disabled) | |
| setenforce 0 || true | |
| sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config | |
| ;; | |
| permissive) | |
| setenforce 0 || true | |
| sed -i 's/^SELINUX=.*/SELINUX=permissive/' /etc/selinux/config | |
| ;; | |
| enforcing) | |
| setenforce 1 || true | |
| sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config | |
| ;; | |
| esac | |
| ############################ | |
| # SYSTEM UPDATE | |
| ############################ | |
| log "Updating system" | |
| dnf -y update | |
| ############################ | |
| # PACKAGES | |
| ############################ | |
| log "Installing packages" | |
| dnf_safe() { | |
| for i in {1..3}; do | |
| dnf -y "$@" && break | |
| sleep 5 | |
| done | |
| } | |
| dnf -y install epel-release | |
| dnf_safe install git curl wget unzip nano tar sqlite | |
| dnf_safe install firewalld | |
| dnf_safe install httpd mod_ssl | |
| dnf_safe install policycoreutils-python-utils | |
| systemctl daemon-reexec | |
| systemctl enable --now httpd | |
| ############################ | |
| # FIREWALL | |
| ############################ | |
| systemctl enable --now firewalld httpd | |
| firewall-cmd --permanent --add-service=http | |
| firewall-cmd --permanent --add-service=https | |
| firewall-cmd --permanent --add-port=3000/tcp | |
| firewall-cmd --reload | |
| ############################ | |
| # DATABASE (optional) | |
| ############################ | |
| if [ "$DB_MODE" = "local" ]; then | |
| log "Installing MariaDB" | |
| dnf -y install mariadb-server | |
| systemctl enable --now mariadb | |
| until mysqladmin ping --silent; do sleep 2; done | |
| mysql -e "CREATE DATABASE IF NOT EXISTS ${DB_NAME};" | |
| mysql -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';" | |
| mysql -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';" | |
| mysql -e "FLUSH PRIVILEGES;" | |
| fi | |
| ############################ | |
| # FORGEJO INSTALL | |
| ############################ | |
| log "Installing Forgejo" | |
| cd /tmp | |
| wget https://codeberg.org/forgejo/forgejo/releases/download/v${FORGEJO_VERSION}/forgejo-${FORGEJO_VERSION}-linux-amd64 | |
| install -m 0755 forgejo-${FORGEJO_VERSION}-linux-amd64 /usr/local/bin/forgejo | |
| ############################ | |
| # USER + DIRS | |
| ############################ | |
| groupadd --system forgejo || true | |
| useradd --system \ | |
| --home /var/lib/forgejo \ | |
| --gid forgejo \ | |
| --shell /bin/bash \ | |
| forgejo || true | |
| mkdir -p /var/lib/forgejo/{custom,data,log} | |
| chown -R forgejo:forgejo /var/lib/forgejo | |
| ############################ | |
| # CONFIG | |
| ############################ | |
| log "Creating Forgejo config" | |
| mkdir -p /var/lib/forgejo/custom/conf | |
| SECRET_KEY=$(openssl rand -hex 32) | |
| INTERNAL_TOKEN=$(openssl rand -hex 32) | |
| cat > /var/lib/forgejo/custom/conf/app.ini <<EOF | |
| APP_NAME = ${APP_NAME} | |
| RUN_MODE = ${RUN_MODE} | |
| [server] | |
| DOMAIN = ${SERVER_NAME} | |
| ROOT_URL = ${APP_URL}/ | |
| HTTP_ADDR = ${HTTP_BIND} | |
| HTTP_PORT = ${HTTP_PORT} | |
| DISABLE_SSH = false | |
| SSH_PORT = ${SSH_PORT} | |
| START_SSH_SERVER = false | |
| [mailer] | |
| ENABLED = ${MAIL_ENABLED} | |
| PROTOCOL = ${SMTP_PROTOCOL} | |
| SMTP_ADDR = ${SMTP_ADDR} | |
| SMTP_PORT = ${SMTP_PORT} | |
| FROM = ${MAIL_FROM} | |
| USER = ${SMTP_USER} | |
| PASSWD = ${SMTP_PASS} | |
| [database] | |
| DB_TYPE = mysql | |
| HOST = ${DB_HOST}:3306 | |
| NAME = ${DB_NAME} | |
| USER = ${DB_USER} | |
| PASSWD = ${DB_PASS} | |
| [security] | |
| INSTALL_LOCK = false | |
| SECRET_KEY = ${SECRET_KEY} | |
| INTERNAL_TOKEN = ${INTERNAL_TOKEN} | |
| PASSWORD_HASH_ALGO = argon2 | |
| [service] | |
| DISABLE_REGISTRATION = ${DISABLE_REGISTRATION} | |
| REQUIRE_SIGNIN_VIEW = ${REQUIRE_SIGNIN_VIEW} | |
| ENABLE_CAPTCHA = ${ENABLE_CAPTCHA} | |
| ALLOW_ONLY_EXTERNAL_REGISTRATION = ${EXTERNAL_REGISTRATION} | |
| REGISTER_EMAIL_CONFIRM = ${REGISTER_EMAIL_CONFIRM} | |
| ENABLE_NOTIFY_MAIL = ${ENABLE_NOTIFY_MAIL} | |
| [repository] | |
| DEFAULT_PRIVATE = private | |
| [session] | |
| PROVIDER = file | |
| [log] | |
| MODE = file | |
| LEVEL = Info | |
| ROOT_PATH = /var/lib/forgejo/log | |
| EOF | |
| chown -R forgejo:forgejo /var/lib/forgejo/custom | |
| chmod 750 /var/lib/forgejo/custom | |
| chmod 640 /var/lib/forgejo/custom/conf/app.ini | |
| ############################ | |
| # SYSTEMD | |
| ############################ | |
| log "Creating service" | |
| cat > /etc/systemd/system/forgejo.service <<EOF | |
| [Unit] | |
| Description=Forgejo | |
| After=network.target | |
| [Service] | |
| User=forgejo | |
| Group=forgejo | |
| WorkingDirectory=/var/lib/forgejo | |
| ExecStart=/usr/local/bin/forgejo web | |
| Restart=always | |
| RestartSec=2s | |
| Environment=USER=forgejo | |
| Environment=HOME=/var/lib/forgejo | |
| Environment=GITEA_WORK_DIR=/var/lib/forgejo | |
| Environment=APP_DATA_PATH=/var/lib/forgejo/data | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| systemctl daemon-reload | |
| systemctl enable forgejo | |
| systemctl start forgejo | |
| ############################ | |
| # SSL | |
| ############################ | |
| log "Generating self-signed cert" | |
| openssl req -x509 -nodes -days 365 \ | |
| -newkey rsa:2048 \ | |
| -keyout ${SSL_KEY} \ | |
| -out ${SSL_CERT} \ | |
| -subj "/C=${CERT_COUNTRY}/ST=${CERT_STATE}/L=${CERT_CITY}/O=${CERT_ORG}/OU=${CERT_UNIT}/CN=${SERVER_NAME}" | |
| chmod 600 /etc/pki/tls/private/forgejo.key | |
| ############################ | |
| # APACHE PROXY | |
| ############################ | |
| log "Configuring Apache" | |
| cat > /etc/httpd/conf.d/forgejo.conf <<EOF | |
| <VirtualHost *:80> | |
| ServerName ${SERVER_NAME} | |
| Redirect / https://${SERVER_NAME}/ | |
| </VirtualHost> | |
| <VirtualHost *:443> | |
| ServerName ${SERVER_NAME} | |
| SSLEngine on | |
| SSLCertificateFile /etc/pki/tls/certs/forgejo.crt | |
| SSLCertificateKeyFile /etc/pki/tls/private/forgejo.key | |
| ProxyPreserveHost On | |
| ProxyPass / http://127.0.0.1:3000/ | |
| ProxyPassReverse / http://127.0.0.1:3000/ | |
| RequestHeader set X-Forwarded-Proto "https" | |
| </VirtualHost> | |
| EOF | |
| setsebool -P httpd_can_network_connect 1 | |
| systemctl restart httpd | |
| ############################ | |
| # CRON | |
| ############################ | |
| cat > /etc/cron.d/forgejo-health <<EOF | |
| */5 * * * * root curl -fs http://127.0.0.1:3000/ || systemctl restart forgejo | |
| 0 2 * * * root dnf -y update --security | |
| EOF | |
| ############################ | |
| # DONE | |
| ############################ | |
| log "Deployment complete" | |
| echo "======================================" | |
| echo " Forgejo is ready" | |
| echo " URL: ${APP_URL}" | |
| echo "======================================" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment