From 18e4149929f927c4ee2a1fa93108bdcc606b3245 Mon Sep 17 00:00:00 2001 From: Peter Wood Date: Wed, 30 Apr 2025 12:54:39 -0400 Subject: [PATCH] Add Gitea setup documentation, environment configuration, and Docker Compose files --- git/Gemini.md | 284 ++++++++++++++++++++++++++++++++++++ git/README.md | 11 ++ git/{ => prev}/.env.example | 5 +- git/prev/app.ini | 103 +++++++++++++ git/{ => prev}/compose.yml | 56 ++++--- 5 files changed, 428 insertions(+), 31 deletions(-) create mode 100644 git/Gemini.md create mode 100644 git/README.md rename git/{ => prev}/.env.example (64%) create mode 100644 git/prev/app.ini rename git/{ => prev}/compose.yml (51%) diff --git a/git/Gemini.md b/git/Gemini.md new file mode 100644 index 0000000..7ce942b --- /dev/null +++ b/git/Gemini.md @@ -0,0 +1,284 @@ +Okay, let's switch gears to run Gitea using Docker and Docker Compose. This is generally the recommended approach as it isolates Gitea and its dependencies. + +We'll still create a user on the *host* system to own the data volumes, ensuring correct permissions *outside* the container. The Gitea container itself runs internally as a user (usually `git`, UID/GID 1000 by default in the official image), and Docker maps the volume permissions. + +**Key Components:** + +1. **`docker-compose.yml`:** Defines the Gitea service and potentially a database service (e.g., PostgreSQL). +2. **Host Directory Structure:** Directories on the host machine to store persistent Gitea data (repos, config, database files, logs). +3. **Host User (`git`):** A user on the host system to own these directories, matching the UID/GID used inside the container. +4. **`app.ini`:** The Gitea configuration file, placed in the host directory structure to be mounted into the container. + +**Steps:** + +**1. Create Host User and Group (if they don't exist)** + +We need a user and group on the host machine. We'll use the standard non-privileged UID/GID `1000`, which the official Gitea Docker image typically uses internally for its `git` user. + +```bash +# Run these commands with sudo +sudo groupadd --gid 1000 git || echo "Group git (GID 1000) likely already exists." +sudo useradd --system --uid 1010 --gid 1010 --comment "Gitea Docker User" --shell /usr/sbin/nologin --home /opt/gitea git || echo "User git (UID 1010) likely already exists." +# Verify (optional) +id git +``` + +* If UID/GID 1000 is already taken on your system, choose another (e.g., 1001) and make sure to specify it in the `docker-compose.yml` using `user: UID:GID`. However, sticking to 1000 is often simplest if possible. +* `--shell /usr/sbin/nologin` prevents this user from being used for interactive logins. +* `--home /opt/gitea` sets a nominal home directory, though we won't rely on it directly. + +**2. Create Host Directory Structure and Initial `app.ini`** + +We'll create a directory (e.g., `/opt/gitea`) on the host to hold all persistent data and configuration. + +```bash +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status. +set -e + +# --- Configuration --- +HOST_GITEA_ROOT="/opt/gitea" # Or choose another location like /srv/gitea +HOST_GITEA_DATA_DIR="${HOST_GITEA_ROOT}/data" +HOST_GITEA_CONFIG_DIR="${HOST_GITEA_ROOT}/config" # Gitea image expects config in /data/gitea/conf +HOST_GITEA_LOG_DIR="${HOST_GITEA_ROOT}/log" # We'll mount this separately for clarity +HOST_USER_UID=1010 # Must match the UID used inside the container (or specified in docker-compose) +HOST_USER_GID=1010 # Must match the GID used inside the container (or specified in docker-compose) + +# --- Pre-checks --- +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root (or using sudo)" + exit 1 +fi +if ! getent passwd "${HOST_USER_UID}" > /dev/null 2>&1; then + echo "ERROR: User with UID ${HOST_USER_UID} does not exist. Please create it first." + exit 1 +fi +if ! getent group "${HOST_USER_GID}" > /dev/null 2>&1; then + echo "ERROR: Group with GID ${HOST_USER_GID} does not exist. Please create it first." + exit 1 +fi + + +echo "--- Gitea Docker Host Setup ---" + +# --- Create Directories --- +echo "[1/3] Creating host directories in ${HOST_GITEA_ROOT}..." +mkdir -pv "${HOST_GITEA_DATA_DIR}" +mkdir -pv "${HOST_GITEA_CONFIG_DIR}" +mkdir -pv "${HOST_GITEA_LOG_DIR}" +echo "Host directories created." + +# --- Create Minimal app.ini --- +# Note: Gitea container expects app.ini at /data/gitea/conf/app.ini +# We will mount HOST_GITEA_CONFIG_DIR to /etc/gitea for easier access, +# but Gitea might ignore it if /data/gitea/conf/app.ini exists from the volume mount. +# A safer approach is often to let Gitea create the first config inside the /data mount +# and then modify it, or mount the specific file. Let's mount the dir /etc/gitea for now. + +GITEA_CONF_FILE="${HOST_GITEA_CONFIG_DIR}/app.ini" +echo "[2/3] Creating minimal configuration file: ${GITEA_CONF_FILE}..." + +cat << EOF > "${GITEA_CONF_FILE}" +; Example Gitea Configuration File for Docker +; Paths here usually refer to locations INSIDE the container. +; For details, see: https://docs.gitea.com/administration/config-cheat-sheet + +APP_NAME = Gitea Docker +RUN_USER = git ; User inside the container +RUN_MODE = prod + +[server] +DOMAIN = git.ptrwd.com ; CHANGE THIS to your actual domain/IP +HTTP_PORT = 3000 ; Port inside the container +ROOT_URL = http://git.ptrwd.com:3000/ ; CHANGE THIS along with DOMAIN +DISABLE_SSH = false +SSH_DOMAIN = %(DOMAIN)s ; Use value from DOMAIN +SSH_PORT = 22 ; Port inside the container (we map 2222 to this externally) +SSH_LISTEN_PORT = 22 ; Make built-in SSH listen on port 22 inside the container +START_SSH_SERVER = true ; Use the built-in SSH server +LFS_START_SERVER = true +LFS_CONTENT_PATH = /data/gitea/lfs ; Path inside the container + +[repository] +ROOT = /data/git/gitea-repositories ; Path inside the container + +[log] +ROOT_PATH = /data/log ; Path inside container (maps to HOST_GITEA_LOG_DIR) +MODE = console,file ; Log to console (for docker logs) and file +LEVEL = Info + +[database] +; === IMPORTANT: Configure your database === +; Option 1: SQLite3 (Simplest, place DB inside the data volume) +DB_TYPE = sqlite3 +PATH = /data/gitea/gitea.db ; Path inside the container +; +; Option 2: PostgreSQL (Recommended for production, use docker-compose service name as host) +; DB_TYPE = postgres +; HOST = db:5432 ; 'db' is the service name in docker-compose.yml +; NAME = gitea +; USER = gitea +; PASSWD = 'YOUR_POSTGRES_PASSWORD' ; Use secrets or env vars in real setup +; SSL_MODE = disable +; +; Option 3: MySQL +; DB_TYPE = mysql +; HOST = db:3306 ; 'db' is the service name in docker-compose.yml +; NAME = gitea +; USER = gitea +; PASSWD = 'YOUR_MYSQL_PASSWORD' ; Use secrets or env vars in real setup +; CHARSET = utf8mb4 + +[service] +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = false +DISABLE_REGISTRATION = false +ENABLE_CAPTCHA = false +REQUIRE_SIGNIN_VIEW = false + +[security] +INSTALL_LOCK = true ; Set to true AFTER first install via web UI +SECRET_KEY = PLEASE_CHANGE_ME_SECRET_KEY_! ; CHANGE THIS! Generate with 'docker exec gitea generate secret SECRET_KEY' +INTERNAL_TOKEN = PLEASE_CHANGE_ME_INTERNAL_TOKEN_! ; CHANGE THIS! Generate with 'docker exec gitea generate secret INTERNAL_TOKEN' +PASSWORD_HASH_ALGO = pbkdf2 ; Default and recommended + +[session] +PROVIDER = file +PROVIDER_CONFIG = /data/sessions ; Path inside the container + +[picture] +AVATAR_UPLOAD_PATH = /data/gitea/avatars ; Path inside the container +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars ; Path inside the container + +[attachment] +PATH = /data/gitea/attachments ; Path inside the container + +EOF +echo "Minimal ${GITEA_CONF_FILE} created." +echo " >> IMPORTANT: Review and edit ${GITEA_CONF_FILE} with your specific settings (DOMAIN, ROOT_URL, Database, Secret Keys)!" + +# --- Set Ownership --- +echo "[3/3] Setting ownership for ${HOST_GITEA_ROOT} to ${HOST_USER_UID}:${HOST_USER_GID}..." +chown -R "${HOST_USER_UID}":"${HOST_USER_GID}" "${HOST_GITEA_ROOT}" +# Set permissions (optional, ownership is key for docker volumes) +# chmod -R u+rwX,go= "${HOST_GITEA_ROOT}" # Give owner full control, deny group/others +chmod 750 "${HOST_GITEA_ROOT}" # Owner rwx, group rx, others --- +find "${HOST_GITEA_ROOT}" -type d -exec chmod 750 {} \; # Dirs: owner rwx, group rx +find "${HOST_GITEA_ROOT}" -type f -exec chmod 640 {} \; # Files: owner rw, group r +echo "Ownership and basic permissions set." + +echo "--- Host Setup Complete ---" +echo "Next steps:" +echo "1. **CRITICAL:** Edit ${GITEA_CONF_FILE} for your specific needs (Domain, Database, Secrets!)." +echo "2. Create the docker-compose.yml file." +echo "3. Run 'docker compose up -d' in the directory containing docker-compose.yml." +``` + +**How to use the script:** + +1. Save the script (e.g., `setup_docker_gitea_host.sh`). +2. Make it executable: `chmod +x setup_docker_gitea_host.sh`. +3. Run with sudo: `sudo ./setup_docker_gitea_host.sh`. +4. **Crucially, edit the generated `/opt/gitea/config/app.ini` file** with your actual domain, database choice, and generate/set real secret keys *before* starting the container. + +**3. Create `docker-compose.yml`** + +Create this file in a convenient location (e.g., in `/opt/gitea` or a dedicated project directory). This example uses PostgreSQL, which is recommended for production. + +```yaml +# /opt/gitea/docker-compose.yml +# or ~/gitea-docker/docker-compose.yml + +networks: + gitea-net: + external: false + +services: + gitea: + image: gitea/gitea:latest # Use a specific version tag in production, e.g., :1.21.5 + container_name: gitea + restart: always + environment: + # All config is primarily done via app.ini now, but you could pass some simpler ones here + - USER_UID=1010 # Matches the host user created + - USER_GID=1010 # Matches the host group created + - GITEA__database__DB_TYPE=postgres # Example: Overriding app.ini via env var if needed + - GITEA__database__HOST=db:5432 # Using double underscore convention + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD=gitea_password # CHANGE THIS! Use docker secrets ideally + networks: + - gitea-net + volumes: + # Mount the main data directory from the host + - ./data:/data # Maps host's ./data (relative to compose file) to container's /data + # Mount the config directory separately (optional, but explicit) + - ./config:/etc/gitea # Maps host's ./config to container's /etc/gitea + # Mount log directory + - ./log:/data/log # Maps host's ./log to container's /data/log (matches app.ini) + # Timezone consistency + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" # Map host port 3000 to container port 3000 (HTTP) + - "2222:22" # Map host port 2222 to container port 22 (SSH) + depends_on: + db: + condition: service_healthy # Wait for postgres to be healthy + + db: + image: postgres:15 # Use a specific version + container_name: gitea-db + restart: always + environment: + - POSTGRES_USER=gitea # CHANGE THIS if needed + - POSTGRES_PASSWORD=gitea_password # CHANGE THIS! Must match GITEA__database__PASSWD + - POSTGRES_DB=gitea # CHANGE THIS if needed + networks: + - gitea-net + volumes: + # Persist postgres data on the host - create a 'postgres' dir next to 'data', 'config', 'log' + - ./postgres:/var/lib/postgresql/data + healthcheck: + # Basic check to see if postgres is ready to accept connections + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 10s + timeout: 5s + retries: 5 + + volumes: + gitea_data: + gitea_config: + postgres_data: + +``` + +**Explanation:** + +* **`user: "1000:1000"` (Optional but good practice):** You can explicitly add this under the `gitea:` service definition to force the container process to run as UID/GID 1000, ensuring it matches the host directory ownership. The official image usually handles this, but being explicit can prevent permission issues. +* **Volumes (`./data:/data`, etc.):** We use *bind mounts*. This maps the directories we created on the host (`/opt/gitea/data`, `/opt/gitea/config`, etc.) directly into the specified paths inside the container. Docker uses the ownership we set on the host directories (`chown 1000:1000`). +* **`app.ini` Location:** The Gitea image typically looks for `app.ini` within its data directory (`/data/gitea/conf/app.ini`). By mounting `./config:/etc/gitea` and `./data:/data`, the container *should* find the config. If you have issues, you might need to adjust the volume mount for config or ensure the `app.ini` is placed at `/opt/gitea/data/gitea/conf/app.ini` on the host *before* starting. Mounting `/etc/gitea` is often cleaner if the image respects `GITEA_CUSTOM`. For simplicity, the setup script places it in `./config`, matching the volume mount. Adjust if Gitea doesn't pick it up. +* **Database:** The `db` service uses the official Postgres image. Its data is persisted in `./postgres` on the host. The Gitea container connects to it using the service name `db` as the hostname. **Change the default passwords!** +* **Ports:** `3000:3000` maps the web UI port. `2222:22` maps host port 2222 to the container's SSH port 22 (make sure your host's firewall allows port 2222). +* **Networks:** A dedicated network `gitea-net` allows the containers to communicate easily using service names (`gitea`, `db`). +* **Healthcheck:** Ensures Gitea only starts *after* PostgreSQL is ready. + +**4. Running Gitea** + +1. Navigate to the directory where you saved `docker-compose.yml` (e.g., `/opt/gitea`). +2. Ensure you have edited `/opt/gitea/config/app.ini` appropriately (Domain, DB, **Secrets**). Generate secrets using `docker run --rm gitea/gitea:latest gitea generate secret SECRET_KEY` etc., if needed. +3. Start the services in detached mode: + ```bash + cd /opt/gitea + docker compose up -d + ``` +4. Check the logs: + ```bash + docker compose logs -f gitea + docker compose logs -f db + ``` +5. Access Gitea in your browser at `http://:3000`. +6. Clone via SSH using `ssh://git@:2222/user/repo.git`. + +This Docker setup provides isolation, easier dependency management (database), and uses host volumes with correct permissions managed by the `git` (UID/GID 1000) user on the host. \ No newline at end of file diff --git a/git/README.md b/git/README.md new file mode 100644 index 0000000..6ee5eb8 --- /dev/null +++ b/git/README.md @@ -0,0 +1,11 @@ + +# Gitea + +## Why the fuck did I choose to run this? + +I have no idea and it's giving me problems when I try to set it up but I've tried several times now and I can't give up! + +## Installation tutorial + +In video form! +🔗 diff --git a/git/.env.example b/git/prev/.env.example similarity index 64% rename from git/.env.example rename to git/prev/.env.example index 56bc03c..0888d97 100644 --- a/git/.env.example +++ b/git/prev/.env.example @@ -3,4 +3,7 @@ POSTGRES_HOST=db POSTGRES_PORT=5432 POSTGRES_DB=gitea POSTGRES_USER= -POSTGRES_PASSWORD= \ No newline at end of file +POSTGRES_PASSWORD= + +SSH_PORT="2221" +WEB_PORT="3200" diff --git a/git/prev/app.ini b/git/prev/app.ini new file mode 100644 index 0000000..a672a61 --- /dev/null +++ b/git/prev/app.ini @@ -0,0 +1,103 @@ +APP_NAME = Gitea: Git with a cup of tea +RUN_MODE = prod +RUN_USER = git +WORK_PATH = /data/gitea + +[repository] +ROOT = /data/git/repositories + +[repository.local] +LOCAL_COPY_PATH = /data/gitea/tmp/local-repo + +[repository.upload] +TEMP_PATH = /data/gitea/uploads + +[server] +APP_DATA_PATH = /data/gitea +DOMAIN = git.ptrwd.com +SSH_DOMAIN = git.ptrwd.com +HTTP_PORT = 3000 +ROOT_URL = https://git.ptrwd.com +DISABLE_SSH = false +SSH_PORT = 2221 +SSH_LISTEN_PORT = 22 +LFS_START_SERVER = true +LFS_JWT_SECRET = cfXD6Y5d3JrMXWgABh-eUtMd3R9Eu03wqNwc_g8BBSM +OFFLINE_MODE = true + +[database] +PATH = /data/gitea/gitea.db +DB_TYPE = postgres +HOST = db:5432 +NAME = gitea +USER = gitea +PASSWD = HfBdjQ0Ug2pF5uggkArxI9I0 +LOG_SQL = false +SCHEMA = +SSL_MODE = disable + +[indexer] +ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve + +[session] +PROVIDER_CONFIG = /data/gitea/sessions +PROVIDER = file + +[picture] +AVATAR_UPLOAD_PATH = /data/gitea/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars + +[attachment] +PATH = /data/gitea/attachments + +[log] +MODE = console +LEVEL = info +ROOT_PATH = /data/gitea/log + +[security] +INSTALL_LOCK = true +SECRET_KEY = +REVERSE_PROXY_LIMIT = 1 +REVERSE_PROXY_TRUSTED_PROXIES = * +INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3NDU5NjE2ODJ9.QmA5imRR3NRtpUCjXkMQeoYD4i0fQ8FT92UD7cYX4Go +PASSWORD_HASH_ALGO = pbkdf2 + +[service] +DISABLE_REGISTRATION = true +REQUIRE_SIGNIN_VIEW = false +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = true +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = false +DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true +DEFAULT_ENABLE_TIMETRACKING = false +NO_REPLY_ADDRESS = noreply.git.ptrwd.com + +[lfs] +PATH = /data/git/lfs + +[mailer] +ENABLED = true +SMTP_ADDR = smtp.fastmail.com +SMTP_PORT = 465 +FROM = git@thewood.email +USER = peter@peterwood.dev +PASSWD = 8k3t7v9369622j6g + +[openid] +ENABLE_OPENID_SIGNIN = false +ENABLE_OPENID_SIGNUP = false + +[cron.update_checker] +ENABLED = false + +[repository.pull-request] +DEFAULT_MERGE_STYLE = merge + +[repository.signing] +DEFAULT_TRUST_MODEL = committer + +[oauth2] +JWT_SECRET = jO3fsrBXoFqCNU59k4hkZI_xw1K8ofkDr3wLFkdS5EU diff --git a/git/compose.yml b/git/prev/compose.yml similarity index 51% rename from git/compose.yml rename to git/prev/compose.yml index cba4f98..142f50f 100644 --- a/git/compose.yml +++ b/git/prev/compose.yml @@ -1,52 +1,48 @@ ---- services: server: image: gitea/gitea:latest container_name: gitea-server environment: - - USER_UID=1000 - - USER_GID=1000 + - USER_UID=121 # (europa) id -u git + - USER_GID=65534 # (europa) id -g git - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432} - GITEA__database__NAME=${POSTGRES_DB:?POSTGRES_DB not set} - GITEA__database__USER=${POSTGRES_USER:?POSTGRES_USER not set} - GITEA__database__PASSWD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set} - - GITEA__server__SSH_PORT=2221 + - GITEA__server__SSH_PORT=${SSH_PORT} - GITEA__server__ROOT_URL=https://git.ptrwd.com - # --> (Optional) When using traefik... - # networks: - # - frontend - # <-- - # --> (Optional) When using an internal database... - # - backend - # <-- + networks: + - backend volumes: - gitea-data:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro + - /home/git/.ssh/:/data/git/.ssh ports: - - "3200:3000" - - "2221:22" + - ${WEB_PORT}:3000 + - ${SSH_PORT}:22 depends_on: - db restart: unless-stopped - -db: - image: postgres:14 - container_name: gitea-db - environment: - - POSTGRES_USER=${POSTGRES_USER:?POSTGRES_USER not set} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set} - - POSTGRES_DB=${POSTGRES_DB:?POSTGRES_DB not set} - networks: - - backend - volumes: - - gitea-db:/var/lib/postgresql/data - restart: unless-stopped - - + db: + image: postgres:14 + container_name: gitea-db + environment: + - POSTGRES_USER=${POSTGRES_USER:?POSTGRES_USER not set} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set} + - POSTGRES_DB=${POSTGRES_DB:?POSTGRES_DB not set} + networks: + - backend + volumes: + - gitea-db:/var/lib/postgresql/data + restart: unless-stopped + +networks: + backend: + external: true volumes: gitea-data: driver: local - backend: - external: true \ No newline at end of file + gitea-db: + driver: local