# Gitea with Let's Encrypt Using Docker Compose # The complete installation guide is available on my website https://www.heyvaldemar.com/install-gitea-using-docker-compose/ # Change variables in the `.env` to meet your requirements. # Note that the `.env` file should be in the same directory as `gitea-traefik-letsencrypt-docker-compose.yml`. # Create networks for your services before deploying the configuration using the commands: # `docker network create traefik-network` # `docker network create gitea-network` # Deploy Gitea using Docker Compose: # `docker compose -f gitea-traefik-letsencrypt-docker-compose.yml -p gitea up -d` # Backups # The `backups` container in the configuration is responsible for the following: # 1. **Database Backup**: Creates compressed backups of the PostgreSQL database using pg_dump. # Customizable backup path, filename pattern, and schedule through variables like `POSTGRES_BACKUPS_PATH`, `POSTGRES_BACKUP_NAME`, and `BACKUP_INTERVAL`. # 2. **Application Data Backup**: Compresses and stores backups of the application data on the same schedule. Controlled via variables such as `DATA_BACKUPS_PATH`, `DATA_BACKUP_NAME`, and `BACKUP_INTERVAL`. # 3. **Backup Pruning**: Periodically removes backups exceeding a specified age to manage storage. # Customizable pruning schedule and age threshold with `POSTGRES_BACKUP_PRUNE_DAYS` and `DATA_BACKUP_PRUNE_DAYS`. # By utilizing this container, consistent and automated backups of the essential components of your instance are ensured. # Moreover, efficient management of backup storage and tailored backup routines can be achieved through easy and flexible configuration using environment variables. # # gitea-restore-database.sh Description # This script facilitates the restoration of a database backup. # 1. **Identify Containers**: It first identifies the service and backups containers by name, finding the appropriate container IDs. # 2. **List Backups**: Displays all available database backups located at the specified backup path. # 3. **Select Backup**: Prompts the user to copy and paste the desired backup name from the list to restore the database. # 4. **Stop Service**: Temporarily stops the service to ensure data consistency during restoration. # 5. **Restore Database**: Executes a sequence of commands to drop the current database, create a new one, and restore it from the selected compressed backup file. # 6. **Start Service**: Restarts the service after the restoration is completed. # To make the `gitea-restore-database.shh` script executable, run the following command: # `chmod +x gitea-restore-database.sh` # Usage of this script ensures a controlled and guided process to restore the database from an existing backup. # # gitea-restore-application-data.sh Description # This script is designed to restore the application data. # 1. **Identify Containers**: Similarly to the database restore script, it identifies the service and backups containers by name. # 2. **List Application Data Backups**: Displays all available application data backups at the specified backup path. # 3. **Select Backup**: Asks the user to copy and paste the desired backup name for application data restoration. # 4. **Stop Service**: Stops the service to prevent any conflicts during the restore process. # 5. **Restore Application Data**: Removes the current application data and then extracts the selected backup to the appropriate application data path. # 6. **Start Service**: Restarts the service after the application data has been successfully restored. # To make the `gitea-restore-application-data.sh` script executable, run the following command: # `chmod +x gitea-restore-application-data.sh` # By utilizing this script, you can efficiently restore application data from an existing backup while ensuring proper coordination with the running service. # Author # I’m Vladimir Mikhalev, the Docker Captain, but my friends can call me Valdemar. # https://www.docker.com/captains/vladimir-mikhalev/ # My website with detailed IT guides: https://www.heyvaldemar.com/ # Follow me on YouTube: https://www.youtube.com/channel/UCf85kQ0u1sYTTTyKVpxrlyQ?sub_confirmation=1 # Follow me on Twitter: https://twitter.com/heyValdemar # Follow me on Instagram: https://www.instagram.com/heyvaldemar/ # Follow me on Threads: https://www.threads.net/@heyvaldemar # Follow me on Mastodon: https://mastodon.social/@heyvaldemar # Follow me on Bluesky: https://bsky.app/profile/heyvaldemar.bsky.social # Follow me on Facebook: https://www.facebook.com/heyValdemarFB/ # Follow me on TikTok: https://www.tiktok.com/@heyvaldemar # Follow me on LinkedIn: https://www.linkedin.com/in/heyvaldemar/ # Follow me on GitHub: https://github.com/heyvaldemar # Communication # Chat with IT pros on Discord: https://discord.gg/AJQGCCBcqf # Reach me at ask@sre.gg # Give Thanks # Support on GitHub: https://github.com/sponsors/heyValdemar # Support on Patreon: https://www.patreon.com/heyValdemar # Support on BuyMeaCoffee: https://www.buymeacoffee.com/heyValdemar # Support on Ko-fi: https://ko-fi.com/heyValdemar # Support on PayPal: https://www.paypal.com/paypalme/heyValdemarCOM networks: gitea-network: external: true traefik-network: external: true volumes: gitea-data: gitea-postgres: gitea-postgres-backup: gitea-data-backups: gitea-database-backups: traefik-certificates: services: postgres: image: ${GITEA_POSTGRES_IMAGE_TAG} volumes: - gitea-postgres:/var/lib/postgresql/data environment: POSTGRES_DB: ${GITEA_DB_NAME} POSTGRES_USER: ${GITEA_DB_USER} POSTGRES_PASSWORD: ${GITEA_DB_PASSWORD} networks: - gitea-network healthcheck: test: [ "CMD", "pg_isready", "-q", "-d", "${GITEA_DB_NAME}", "-U", "${GITEA_DB_USER}" ] interval: 10s timeout: 5s retries: 3 start_period: 60s restart: unless-stopped gitea: image: ${GITEA_IMAGE_TAG} volumes: - gitea-data:/${DATA_PATH} - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro environment: GITEA_DATABASE_HOST: postgres GITEA_DATABASE_NAME: ${GITEA_DB_NAME} GITEA_DATABASE_USERNAME: ${GITEA_DB_USER} GITEA_DATABASE_PASSWORD: ${GITEA_DB_PASSWORD} GITEA_ADMIN_USER: ${GITEA_ADMIN_USERNAME} GITEA_ADMIN_PASSWORD: ${GITEA_ADMIN_PASSWORD} GITEA_ADMIN_EMAIL: ${GITEA_ADMIN_EMAIL} GITEA_RUN_MODE: prod GITEA_DOMAIN: ${GITEA_HOSTNAME} GITEA_SSH_DOMAIN: ${GITEA_HOSTNAME} GITEA_ROOT_URL: ${GITEA_URL} GITEA_HTTP_PORT: 3000 GITEA_SSH_PORT: ${GITEA_SHELL_SSH_PORT} GITEA_SSH_LISTEN_PORT: 22 networks: - gitea-network - traefik-network healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/"] interval: 10s timeout: 5s retries: 3 start_period: 90s labels: - "traefik.enable=true" - "traefik.http.routers.gitea.rule=Host(`${GITEA_HOSTNAME}`)" - "traefik.http.routers.gitea.service=gitea" - "traefik.http.routers.gitea.entrypoints=websecure" - "traefik.http.services.gitea.loadbalancer.server.port=3000" - "traefik.http.routers.gitea.tls=true" - "traefik.http.routers.gitea.tls.certresolver=letsencrypt" - "traefik.http.services.gitea.loadbalancer.passhostheader=true" - "traefik.http.routers.gitea.middlewares=compresstraefik" - "traefik.http.middlewares.compresstraefik.compress=true" - "traefik.tcp.routers.gitea-ssh.rule=HostSNI(`*`)" - "traefik.tcp.routers.gitea-ssh.service=gitea-ssh" - "traefik.tcp.routers.gitea-ssh.entrypoints=ssh" - "traefik.tcp.services.gitea-ssh.loadbalancer.server.port=22" - "traefik.docker.network=traefik-network" restart: unless-stopped depends_on: postgres: condition: service_healthy traefik: condition: service_healthy traefik: image: ${TRAEFIK_IMAGE_TAG} command: - "--log.level=${TRAEFIK_LOG_LEVEL}" - "--accesslog=true" - "--api.dashboard=true" - "--api.insecure=true" - "--ping=true" - "--ping.entrypoint=ping" - "--entryPoints.ping.address=:8082" - "--entryPoints.web.address=:80" - "--entryPoints.websecure.address=:443" - "--entryPoints.ssh.address=:${GITEA_SHELL_SSH_PORT}" - "--providers.docker=true" - "--providers.docker.endpoint=unix:///var/run/docker.sock" - "--providers.docker.exposedByDefault=false" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json" - "--metrics.prometheus=true" - "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0" - "--global.checkNewVersion=true" - "--global.sendAnonymousUsage=false" volumes: - /var/run/docker.sock:/var/run/docker.sock - traefik-certificates:/etc/traefik/acme networks: - traefik-network ports: - "${GITEA_SHELL_SSH_PORT}:${GITEA_SHELL_SSH_PORT}" - "80:80" - "443:443" healthcheck: test: ["CMD", "wget", "http://localhost:8082/ping","--spider"] interval: 10s timeout: 5s retries: 3 start_period: 5s labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_HOSTNAME}`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.services.dashboard.loadbalancer.server.port=8080" - "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.services.dashboard.loadbalancer.passhostheader=true" - "traefik.http.routers.dashboard.middlewares=authtraefik" - "traefik.http.middlewares.authtraefik.basicauth.users=${TRAEFIK_BASIC_AUTH}" - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)" - "traefik.http.routers.http-catchall.entrypoints=web" - "traefik.http.routers.http-catchall.middlewares=redirect-to-https" - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" restart: unless-stopped backups: image: ${GITEA_POSTGRES_IMAGE_TAG} command: >- sh -c 'sleep $BACKUP_INIT_SLEEP && while true; do pg_dump -h postgres -p 5432 -d $GITEA_DB_NAME -U $GITEA_DB_USER | gzip > $POSTGRES_BACKUPS_PATH/$POSTGRES_BACKUP_NAME-$(date "+%Y-%m-%d_%H-%M").gz && tar -zcpf $DATA_BACKUPS_PATH/$DATA_BACKUP_NAME-$(date "+%Y-%m-%d_%H-%M").tar.gz $DATA_PATH && find $POSTGRES_BACKUPS_PATH -type f -mtime +$POSTGRES_BACKUP_PRUNE_DAYS | xargs rm -f && find $DATA_BACKUPS_PATH -type f -mtime +$DATA_BACKUP_PRUNE_DAYS | xargs rm -f; sleep $BACKUP_INTERVAL; done' volumes: - gitea-postgres-backup:/var/lib/postgresql/data - gitea-data:${DATA_PATH} - gitea-data-backups:${DATA_BACKUPS_PATH} - gitea-database-backups:${POSTGRES_BACKUPS_PATH} environment: GITEA_DB_NAME: ${GITEA_DB_NAME} GITEA_DB_USER: ${GITEA_DB_USER} PGPASSWORD: ${GITEA_DB_PASSWORD} BACKUP_INIT_SLEEP: ${BACKUP_INIT_SLEEP} BACKUP_INTERVAL: ${BACKUP_INTERVAL} POSTGRES_BACKUP_PRUNE_DAYS: ${POSTGRES_BACKUP_PRUNE_DAYS} DATA_BACKUP_PRUNE_DAYS: ${DATA_BACKUP_PRUNE_DAYS} POSTGRES_BACKUPS_PATH: ${POSTGRES_BACKUPS_PATH} DATA_BACKUPS_PATH: ${DATA_BACKUPS_PATH} DATA_PATH: ${DATA_PATH} POSTGRES_BACKUP_NAME: ${POSTGRES_BACKUP_NAME} DATA_BACKUP_NAME: ${DATA_BACKUP_NAME} networks: - gitea-network restart: unless-stopped depends_on: postgres: condition: service_healthy