commit 978a4a085bcf5712cc340a7394e1f458ed954266 Author: Amirhossein Khalili Date: Sun Mar 22 23:06:41 2026 +0800 initial commit diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..52f24d1 --- /dev/null +++ b/.env.sample @@ -0,0 +1,34 @@ +# GITEA CORE CONFIGURATION +GITEA_EXTERNAL_URL=https://git.example.com # http:// +GITEA_ROOT_USER=admin +GITEA_ROOT_PASSWORD=ChangeMe123 # Initial admin password +GITEA_ROOT_EMAIL=admin@example.com +GITEA_DATA_PATH=./gitea-data # Persisted data directory + +# DATABASE +GITEA_DB_TYPE=postgres +GITEA_DB_HOST=db:5432 +GITEA_DB_NAME=gitea +GITEA_DB_USER=gitea +GITEA_DB_PASSWORD=ChangeDbPass123 + +# PORTS +HTTP_PORT=3000 # internal Gitea HTTP (inside container) +SSH_PORT=2222 # exposed SSH from host -> container + +# SMTP / EMAIL SETTINGS +SMTP_ENABLE=false +SMTP_HOST=smtp.mailgun.org +SMTP_PORT=587 +SMTP_USER= +SMTP_PASS= +SMTP_FROM=git@example.com +SMTP_SKIP_VERIFY=true + +# OPTIONAL: LETSENCRYPT / REVERSE PROXY (if you mimic GitLab style) +LETSENCRYPT_ENABLE=false +LETSENCRYPT_EMAIL=admin@example.com + +# OPTIONAL: Custom SSL Configuration +SSL_CERT_PATH=/etc/letsencrypt/live/git.example.com/fullchain.pem +SSL_KEY_PATH=/etc/letsencrypt/live/git.example.com/privkey.pem diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8abe1dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.env + +gitea-data/ + +*.log +*.tmp +*.bak + +.DS_Store +Thumbs.db + +custom-ssl/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..648a869 --- /dev/null +++ b/README.md @@ -0,0 +1,163 @@ +# Gitea Self‑Hosted Deployment + +This repository provides a **simple automated deployment for a self‑hosted Gitea server** using Docker Compose. + +It is designed to make deploying a production‑ready Git server easy with: + +- Docker Compose deployment +- PostgreSQL database +- Optional SMTP email +- Optional HTTPS support +- Automated bootstrap script +- Persistent data storage + + +# Requirements + +Minimum recommended: + +- Linux server (Ubuntu / Debian) +- Docker +- Docker Compose +- 2 CPU cores +- 2‑4GB RAM +- 10GB disk space + + +# Quick Start + +Clone the repository: +``` +git clone +cd gitea-deployment +``` + +Run the bootstrap script: +``` +chmod +x run.sh +./run.sh +``` + +On first run the script will: +- Create `.env` from `.env.sample` +- Ask you to configure settings + +Edit `.env`: +``` +nano .env +``` + +Set at minimum: +``` +GITEA_EXTERNAL_URL +GITEA_ROOT_USER +GITEA_ROOT_PASSWORD +GITEA_ROOT_EMAIL +``` + +Then run again: +``` +./run.sh +``` + + +# Access Gitea + +After deployment: +``` +http://YOUR_SERVER_IP +``` + +or +``` +https://your-domain.com +``` + + +# Data Persistence + +All persistent data is stored in: +``` +./gitea-data +``` + +Structure: +``` +gitea-data/ +├─ gitea/ +└─ postgres/ +``` + +Back up this directory to preserve: + +- repositories +- database +- attachments +- configuration + + +# Enabling HTTPS + +Set in `.env`: +``` +GITEA_EXTERNAL_URL=https://git.example.com +SSL_CERT_PATH=/etc/letsencrypt/live/git.example.com/fullchain.pem +SSL_KEY_PATH=/etc/letsencrypt/live/git.example.com/privkey.pem +``` + +During deployment the `setup-ssl.sh` script will copy certificates to: +``` +/data/https/cert.pem +/data/https/key.pem +``` + +Gitea will automatically use them for HTTPS. + + +# Managing the Server + +View logs: +``` +docker compose logs -f +``` + +Stop services: +``` +docker compose down +``` + +Restart: +``` +docker compose restart +``` + +Update Gitea: +``` +docker compose pull +docker compose up -d +``` + + +# Repository Structure +``` +gitea-deployment +├─ docker-compose.yml +├─ run.sh +├─ .env.sample +├─ README.md +└─ scripts + ├─ setup-swap.sh + └─ setup-ssl.sh +``` + + +# Notes + +- The first time Gitea starts it will initialize the database automatically. +- Admin credentials are configured through `.env`. +- SMTP is optional but recommended for production. + + +# License + +MIT diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..440790b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,63 @@ +version: "3.9" + +services: + + db: + image: postgres:15 + container_name: gitea-db + restart: always + environment: + POSTGRES_DB: ${GITEA_DB_NAME} + POSTGRES_USER: ${GITEA_DB_USER} + POSTGRES_PASSWORD: ${GITEA_DB_PASSWORD} + volumes: + - ${GITEA_DATA_PATH}/postgres:/var/lib/postgresql/data + networks: + - gitea_net + + gitea: + image: gitea/gitea:latest + container_name: gitea-server + restart: always + depends_on: + - db + + environment: + USER_UID: 1000 + USER_GID: 1000 + + GITEA__server__ROOT_URL: ${GITEA_EXTERNAL_URL} + GITEA__server__DOMAIN: ${GITEA_DOMAIN} + GITEA__server__SSH_DOMAIN: ${GITEA_DOMAIN} + GITEA__server__SSH_PORT: ${SSH_PORT} + + GITEA__database__DB_TYPE: ${GITEA_DB_TYPE} + GITEA__database__HOST: ${GITEA_DB_HOST} + GITEA__database__NAME: ${GITEA_DB_NAME} + GITEA__database__USER: ${GITEA_DB_USER} + GITEA__database__PASSWD: ${GITEA_DB_PASSWORD} + + GITEA__security__INSTALL_LOCK: true + + GITEA__mailer__ENABLED: ${SMTP_ENABLE} + GITEA__mailer__HOST: ${SMTP_HOST}:${SMTP_PORT} + GITEA__mailer__USER: ${SMTP_USER} + GITEA__mailer__PASSWD: ${SMTP_PASS} + GITEA__mailer__FROM: ${SMTP_FROM} + GITEA__mailer__SKIP_VERIFY: ${SMTP_SKIP_VERIFY} + + volumes: + - ${GITEA_DATA_PATH}/gitea:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + + ports: + - "${HTTP_PORT}:3000" + - "${SSH_PORT}:22" + + networks: + - gitea_net + +networks: + gitea_net: + driver: bridge diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..e336c85 --- /dev/null +++ b/run.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +set -e + +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo "" +echo "========================================" +echo " Gitea Deployment Bootstrapper" +echo "========================================" +echo "" + +if [ ! -f ".env" ]; then + echo -e "${YELLOW}[INFO] .env file not found.${NC}" + echo "Creating .env from template..." + cp .env.sample .env + + echo "" + echo -e "${YELLOW}Please edit .env and rerun this script.${NC}" + exit 1 +fi + +source .env + +if [[ -z "$GITEA_EXTERNAL_URL" || "$GITEA_EXTERNAL_URL" == *"example.com"* ]]; then + echo -e "${RED}[ERROR] Invalid GITEA_EXTERNAL_URL in .env${NC}" + exit 1 +fi + +if [[ -z "$GITEA_ROOT_PASSWORD" || ${#GITEA_ROOT_PASSWORD} -lt 8 ]]; then + echo -e "${RED}[ERROR] GITEA_ROOT_PASSWORD must be at least 8 characters.${NC}" + exit 1 +fi + +echo -e "${GREEN}[INFO] Configuration validated.${NC}" + +echo "" +echo "[STEP] Checking swap configuration..." +./scripts/setup-swap.sh || true + +echo "" +echo "[STEP] Preparing SSL certificates (if HTTPS enabled)..." +./scripts/setup-ssl.sh || true + +echo "" +echo "[STEP] Creating data directories..." +mkdir -p ${GITEA_DATA_PATH}/gitea +mkdir -p ${GITEA_DATA_PATH}/postgres + +echo "" +echo "[STEP] Starting containers..." +docker compose up -d + +echo "" +echo -e "${GREEN}========================================${NC}" +echo -e "${GREEN}Gitea deployment started successfully${NC}" +echo -e "${GREEN}========================================${NC}" +echo "" + +echo "Access your instance at:" +echo " $GITEA_EXTERNAL_URL" +echo "" + +echo "Container status:" +docker compose ps diff --git a/scripts/setup-ssl.sh b/scripts/setup-ssl.sh new file mode 100644 index 0000000..ecb339b --- /dev/null +++ b/scripts/setup-ssl.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -e + +if [ ! -f ".env" ]; then + echo "[ERROR] .env file not found. Skipping SSL setup." + exit 1 +fi + +source .env + +if [[ ! "$GITEA_EXTERNAL_URL" == https://* ]]; then + echo "[INFO] HTTPS not enabled in GITEA_EXTERNAL_URL. Skipping SSL setup." + exit 0 +fi + +if [[ -z "$SSL_CERT_PATH" || -z "$SSL_KEY_PATH" ]]; then + echo "[INFO] SSL_CERT_PATH or SSL_KEY_PATH not set. Skipping SSL copy." + exit 0 +fi + +if [ ! -f "$SSL_CERT_PATH" ]; then + echo "[ERROR] Certificate file not found: $SSL_CERT_PATH" + exit 1 +fi + +if [ ! -f "$SSL_KEY_PATH" ]; then + echo "[ERROR] Key file not found: $SSL_KEY_PATH" + exit 1 +fi + +echo "[INFO] Preparing Gitea SSL directory..." + +mkdir -p ${GITEA_DATA_PATH}/gitea/https + +echo "[INFO] Copying SSL certificates..." + +cp "$SSL_CERT_PATH" ${GITEA_DATA_PATH}/gitea/https/cert.pem +cp "$SSL_KEY_PATH" ${GITEA_DATA_PATH}/gitea/https/key.pem + +chmod 600 ${GITEA_DATA_PATH}/gitea/https/key.pem + +echo "[SUCCESS] SSL certificates copied." + +echo "Gitea will load them from:" +echo " /data/https/cert.pem" +echo " /data/https/key.pem" diff --git a/scripts/setup-swap.sh b/scripts/setup-swap.sh new file mode 100644 index 0000000..041c866 --- /dev/null +++ b/scripts/setup-swap.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +echo -e "${CYAN}--- System Swap Space Check ---${NC}" + +SWAP_SIZE=$(free -m | awk '/^Swap:/ {print $2}') + +if [ "$SWAP_SIZE" -gt "0" ]; then + echo -e "${GREEN}[OK] Swap space is already configured ($SWAP_SIZE MB). Skipping creation.${NC}" + exit 0 +fi + +RAM_SIZE=$(free -m | awk '/^Mem:/ {print $2}') + +echo -e "${YELLOW}[WARNING] No swap space detected on this server!${NC}" +if [ "$RAM_SIZE" -le "4500" ]; then + echo -e "${RED}[CRITICAL] Your server has ~4GB RAM ($RAM_SIZE MB). A 4GB swap file is HIGHLY recommended.${NC}" +else + echo -e "${CYAN}Your server has plenty of RAM ($RAM_SIZE MB), but adding a swap file is still a safe fallback.${NC}" +fi + +echo "" +read -p "Do you want to automatically create a 4GB swap file now? (Requires sudo password) (y/n): " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo -e "${YELLOW}Skipping swap creation. If Gitea crashes, please create swap manually.${NC}" + exit 0 +fi + +echo -e "${CYAN}Allocating 4GB swap file... This may take a moment.${NC}" +sudo fallocate -l 4G /swapfile + +if [ $? -ne 0 ]; then + echo -e "${RED}[ERROR] Failed to allocate space. Your disk might be full.${NC}" + exit 1 +fi + +echo -e "${CYAN}Securing file permissions...${NC}" +sudo chmod 600 /swapfile + +echo -e "${CYAN}Formatting as swap...${NC}" +sudo mkswap /swapfile + +echo -e "${CYAN}Enabling swap...${NC}" +sudo swapon /swapfile + +if grep -q "/swapfile" /etc/fstab; then + echo -e "${YELLOW}[INFO] /swapfile entry already exists in /etc/fstab.${NC}" +else + echo -e "${CYAN}Adding swap to /etc/fstab to survive reboots...${NC}" + echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab > /dev/null +fi + +NEW_SWAP=$(free -m | awk '/^Swap:/ {print $2}') +if [ "$NEW_SWAP" -gt "0" ]; then + echo -e "${GREEN}[SUCCESS] 4GB Swap space successfully created and enabled!${NC}" +else + echo -e "${RED}[ERROR] Something went wrong. Swap is still reporting 0 MB.${NC}" +fi