# Environment Variables Documentation This document provides a comprehensive list of all environment variables supported by Gitea Mirror. These can be used to configure the application via Docker or other deployment methods. ## Environment Variables and UI Interaction When environment variables are set: 1. They are loaded on application startup 2. Values are stored in the database on first load 3. The UI will display these values and they can be modified 4. UI changes are saved to the database and persist 5. Environment variables provide initial defaults but don't override UI changes **Note**: Some critical settings like `GITEA_LFS`, `MIRROR_RELEASES`, and `MIRROR_METADATA` will be visible and configurable in the UI even when set via environment variables. ## Table of Contents - [Core Configuration](#core-configuration) - [HTTPS / TLS](#https--tls) - [GitHub Configuration](#github-configuration) - [Gitea Configuration](#gitea-configuration) - [Mirror Options](#mirror-options) - [Automation Configuration](#automation-configuration) - [Database Cleanup Configuration](#database-cleanup-configuration) - [Authentication Configuration](#authentication-configuration) - [Docker Configuration](#docker-configuration) ## Core Configuration Essential application settings required for running Gitea Mirror. | Variable | Description | Default | Required | |----------|-------------|---------|----------| | `NODE_ENV` | Application environment | `production` | No | | `HOST` | Server host binding | `0.0.0.0` | No | | `PORT` | Server port | `4321` | No | | `BASE_URL` | Application base path. Use `/` for root deployments, or a prefix such as `/mirror` when serving behind a reverse-proxy path prefix. | `/` | No | | `DATABASE_URL` | Database connection URL | `sqlite://data/gitea-mirror.db` | No | | `BETTER_AUTH_SECRET` | Secret key for session signing (generate with: `openssl rand -base64 32`) | - | Yes | | `BETTER_AUTH_URL` | Authentication origin (scheme + host only, e.g. `https://git.example.com`). Do **not** include a path — any path is automatically stripped, and `BASE_URL` is applied separately. | `http://localhost:4321` | No | | `PUBLIC_BETTER_AUTH_URL` | Client-side auth origin for multi-origin access (same rule: origin only, no path). Set this to your primary domain when you need to access the app from different origins (e.g., both IP and domain). The client will use this URL for all auth requests instead of the current browser origin. | - | No | | `BETTER_AUTH_TRUSTED_ORIGINS` | Trusted origins for authentication requests. Comma-separated list of URLs. Use this to specify additional access URLs (e.g., local IP + domain: `http://10.10.20.45:4321,https://gitea-mirror.mydomain.tld`), SSO providers, reverse proxies, etc. | - | No | | `BETTER_AUTH_LOG_LEVEL` | Better Auth logger verbosity. Set to `debug` to surface the full SSO/OIDC sign-in and callback trace when troubleshooting authentication. Accepted values: `debug`, `info`, `warn`, `error`. (Better Auth does **not** use the `DEBUG` env var.) | `warn` | No | | `ENCRYPTION_SECRET` | Optional encryption key for tokens (generate with: `openssl rand -base64 48`) | - | No | ## HTTPS / TLS Gitea Mirror can terminate TLS directly via the underlying `@astrojs/node` adapter — useful when you don't want a separate reverse proxy. When both variables below are set, the server starts as a real HTTPS listener instead of HTTP. | Variable | Description | Default | Required | |----------|-------------|---------|----------| | `SERVER_CERT_PATH` | Absolute path to the TLS certificate (PEM). Set together with `SERVER_KEY_PATH` to enable HTTPS. | - | No | | `SERVER_KEY_PATH` | Absolute path to the TLS private key (PEM). Set together with `SERVER_CERT_PATH` to enable HTTPS. | - | No | **Example (systemd or `.env`):** ```bash SERVER_CERT_PATH=/etc/ssl/gitea-mirror/cert.pem SERVER_KEY_PATH=/etc/ssl/gitea-mirror/key.pem PORT=443 BETTER_AUTH_URL=https://mirror.example.com BETTER_AUTH_TRUSTED_ORIGINS=https://mirror.example.com ``` Notes: - The process must have read access to both files. When binding to `PORT=443`, grant the binary the `CAP_NET_BIND_SERVICE` capability (or run as a user allowed to bind privileged ports) rather than running as root. - If you already terminate TLS at a reverse proxy (nginx, Traefik, Caddy), leave these unset and let the proxy handle certificates. - Works in Docker too — mount your certs and set both paths to locations inside the container. ## GitHub Configuration Settings for connecting to the source host. GitHub is the default and, together with a Gitea destination, the supported path; every other source or destination is beta. GitLab and Gitea/Forgejo (including Codeberg) are selected with `SOURCE_PROVIDER`; the username and token variables below then hold the account and token for that host. See [SOURCE_PROVIDERS.md](SOURCE_PROVIDERS.md) for what each source supports. ### Basic Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `SOURCE_PROVIDER` | Which host repositories are pulled from. `gitea` also covers Forgejo and Codeberg. Anything other than `github` is beta. | `github` | `github`, `gitlab`, `gitea` | | `SOURCE_URL` | Base URL of the GitLab or Gitea/Forgejo instance. Ignored for GitHub, which uses `GH_API_URL`. | `https://gitlab.com` for GitLab, `https://codeberg.org` for Gitea | e.g. `https://gitlab.example.com` | | `GITHUB_USERNAME` | Your username on the source host | - | - | | `GITHUB_TOKEN` | Personal access token for the source host. GitHub needs the `repo` and `admin:org` scopes, GitLab `read_api` and `read_repository`, Gitea/Forgejo `read:repository`, `read:user` and `read:organization`. | - | - | | `GITHUB_TYPE` | GitHub account type | `personal` | `personal`, `organization` | | `GH_API_URL` | GitHub API base URL. Override this to point at GitHub Enterprise Server or Enterprise Cloud with data residency. | `https://api.github.com` | e.g. `https://ghe.example.com/api/v3`, `https://api.TENANT.ghe.com` | ### GitLab and Gitea/Forgejo sources ```bash # Mirror from a self hosted GitLab SOURCE_PROVIDER=gitlab SOURCE_URL=https://gitlab.example.com GITHUB_USERNAME=my-gitlab-user GITHUB_TOKEN=glpat-... # Mirror from Codeberg (Forgejo) SOURCE_PROVIDER=gitea GITHUB_USERNAME=my-codeberg-user GITHUB_TOKEN=... ``` Code, tags, wiki and LFS are mirrored from every source, and releases with their assets from GitHub and Gitea/Forgejo sources. Issues, pull requests, labels, milestones and star lists need a GitHub source and are skipped for the others. Once repositories have been imported the source is locked, and once anything has been mirrored the Gitea server URL is locked. A `SOURCE_PROVIDER`, `SOURCE_URL` or `GITEA_URL` value that disagrees with a locked host is ignored on boot with a warning; change the host on the Configuration page, where the change asks for confirmation. ### GitHub Enterprise (GHES / GHEC with data residency) Set `GH_API_URL` to point Octokit at a non-`github.com` API endpoint: ```bash # GitHub Enterprise Server (self-hosted) GH_API_URL=https://ghe.example.com/api/v3 # GitHub Enterprise Cloud with data residency GH_API_URL=https://api.TENANT.ghe.com ``` Standard GitHub Enterprise Cloud on `github.com` works with the default — no override needed. Use a personal access token issued by the target Enterprise instance for `GITHUB_TOKEN`. ### Repository Selection | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `PRIVATE_REPOSITORIES` | Include private repositories | `false` | `true`, `false` | | `PUBLIC_REPOSITORIES` | Include public repositories | `true` | `true`, `false` | | `INCLUDE_ARCHIVED` | Include archived repositories | `false` | `true`, `false` | | `INCLUDE_COLLABORATOR_REPOS` | Include repositories where you are a collaborator (not just owned). Set to `false` to limit imports to repos you own. | `true` | `true`, `false` | | `SKIP_FORKS` | Skip forked repositories | `false` | `true`, `false` | | `MIRROR_STARRED` | Mirror starred repositories | `false` | `true`, `false` | | `MIRROR_STARRED_LISTS` | Optional comma-separated GitHub Star List names to mirror (only used when `MIRROR_STARRED=true`) | - | Comma-separated list names (empty = all starred repos) | | `STARRED_REPOS_ORG` | Organization name for starred repos | `starred` | Any string | | `STARRED_REPOS_MODE` | How starred repos are mirrored | `dedicated-org` | `dedicated-org`, `preserve-owner` | | `STARRED_DUPLICATE_STRATEGY` | Name collision strategy when two starred repos share a name from different owners (`suffix` = `repo-owner`, `prefix` = `owner-repo`) | `suffix` | `suffix`, `prefix`, `owner-org` | ### Organization Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `MIRROR_ORGANIZATIONS` | Mirror organization repositories | `false` | `true`, `false` | | `PRESERVE_ORG_STRUCTURE` | Preserve GitHub organization structure in Gitea | `false` | `true`, `false` | | `ONLY_MIRROR_ORGS` | Only mirror organization repos (skip personal); sets `skipPersonalRepos: true` in GitHub config | `false` | `true`, `false` | | `INCLUDE_ORGANIZATIONS` | Opt-in allowlist: only mirror repos from these organizations (empty = all orgs you belong to). Sets `includeOrganizations` in GitHub config | - | Comma-separated org names | | `MIRROR_STRATEGY` | Repository organization strategy | `preserve` | `preserve`, `single-org`, `flat-user`, `mixed` | ### Advanced Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `SKIP_STARRED_ISSUES` | Enable lightweight mode for starred repos (skip issues) | `false` | `true`, `false` | | `AUTO_MIRROR_STARRED` | Automatically mirror starred repos during scheduled syncs and "Mirror All". When `false`, starred repos are imported for browsing but must be mirrored individually. | `false` | `true`, `false` | ## Gitea Configuration Settings for the destination. Gitea and Forgejo are pull mirrors; GitHub and GitLab are push targets served by the push engine (see [PUSH_TARGETS.md](PUSH_TARGETS.md)). The `GITEA_*` names apply to every destination kind. ### Connection Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `DESTINATION_PROVIDER` | Which host mirrors are created on. Gitea and Forgejo share one API (labels and hints differ). GitHub and GitLab receive `git push` of branches and tags from this app. Anything other than `gitea` is beta. | `gitea` | `gitea`, `forgejo`, `github`, `gitlab` | | `GITEA_URL` | Destination instance URL. Optional for GitHub and GitLab, which default to github.com and gitlab.com; set it for GitHub Enterprise Server or a self hosted GitLab. | - | Valid URL | | `GITEA_EXTERNAL_URL` | Optional external/browser URL used for dashboard links. API and mirroring still use `GITEA_URL`. | - | Valid URL | | `GITEA_TOKEN` | Gitea access token | - | - | | `GITEA_USERNAME` | Gitea username | - | - | | `GITEA_ORGANIZATION` | Default organization for single-org strategy | `github-mirrors` | Any string | ### Push Targets (GitHub and GitLab destinations) | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `MIRROR_CLONE_DIR` | Where the push engine keeps its bare clones, one per repository. | `/mirrors` | Absolute or relative path | | `PUSH_CONCURRENCY` | How many git fetch or push operations run at once across all repositories. | `2` | 1 to 32 | ### Repository Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `GITEA_ORG_VISIBILITY` | Default organization visibility | `public` | `public`, `private`, `limited`, `default` | | `GITEA_MIRROR_INTERVAL` | Mirror sync interval - **automatically enables scheduled mirroring when set** | `8h` | Duration string (e.g., `30m`, `1h`, `8h`, `24h`, `1d`) or seconds | | `GITEA_LFS` | Enable LFS support (requires LFS on Gitea server) - Shows in UI | `false` | `true`, `false` | | `GITEA_CREATE_ORG` | Auto-create organizations | `true` | `true`, `false` | | `GITEA_PRESERVE_VISIBILITY` | Preserve GitHub repo visibility in Gitea | `false` | `true`, `false` | ### Template Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `GITEA_TEMPLATE_OWNER` | Template repository owner | - | Any string | | `GITEA_TEMPLATE_REPO` | Template repository name | - | Any string | ### Topic Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `GITEA_ADD_TOPICS` | Add topics to repositories | `true` | `true`, `false` | | `GITEA_TOPIC_PREFIX` | Prefix for repository topics | - | Any string | ### Fork Handling | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `GITEA_FORK_STRATEGY` | How to handle forked repositories | `reference` | `skip`, `reference`, `full-copy` | ### Additional Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `GITEA_SKIP_TLS_VERIFY` | Skip TLS certificate verification (WARNING: insecure) | `false` | `true`, `false` | ## Mirror Options Control what content gets mirrored from GitHub to Gitea. | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `MIRROR_RELEASES` | Mirror GitHub releases | `false` | `true`, `false` | | `RELEASE_LIMIT` | Maximum number of releases to mirror per repository | `10` | Number (1-100) | | `RELEASE_ASSET_LIMIT` | Upload release assets only for the newest N mirrored releases. Older releases still get their notes and tag. Unset means assets for every mirrored release, `0` means release notes only. Lowering it never deletes assets already uploaded | unset (all) | Number (0 or more) | | `MIRROR_WIKI` | Mirror wiki content | `false` | `true`, `false` | | `MIRROR_METADATA` | Master toggle for metadata mirroring | `false` | `true`, `false` | | `MIRROR_ISSUES` | Mirror issues (requires MIRROR_METADATA=true) | `false` | `true`, `false` | | `MIRROR_PULL_REQUESTS` | Mirror pull requests (requires MIRROR_METADATA=true) | `false` | `true`, `false` | | `MIRROR_LABELS` | Mirror labels (requires MIRROR_METADATA=true) | `false` | `true`, `false` | | `MIRROR_MILESTONES` | Mirror milestones (requires MIRROR_METADATA=true) | `false` | `true`, `false` | | `MIRROR_ISSUE_CONCURRENCY` | Number of issues processed in parallel. Set above `1` to speed up mirroring at the risk of out-of-order creation. | `3` | Integer ≥ 1 | | `MIRROR_PULL_REQUEST_CONCURRENCY` | Number of pull requests processed in parallel. Values above `1` may cause ordering differences. | `5` | Integer ≥ 1 | > **Ordering vs Throughput:** Metadata now mirrors sequentially by default to preserve chronology. Increase the concurrency variables only if you can tolerate minor out-of-order entries. ## Automation Configuration Configure automatic scheduled mirroring. ### Basic Schedule Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `SCHEDULE_ENABLED` | Enable automatic mirroring. **When set to `true`, automatically imports and mirrors all repositories on startup** (v3.5.3+) | `false` | `true`, `false` | | `SCHEDULE_INTERVAL` | Interval in seconds or cron expression. **Supports cron syntax for scheduled runs** (e.g., `"0 2 * * *"` for 2 AM daily) | `3600` | Number (seconds) or cron string | | `DELAY` | Legacy: same as SCHEDULE_INTERVAL | `3600` | Number (seconds) | > **🚀 Auto-Start Feature (v3.5.3+)** > Setting either `SCHEDULE_ENABLED=true` or `GITEA_MIRROR_INTERVAL` triggers auto-start functionality where the service will: > 1. **Import** all GitHub repositories on startup > 2. **Mirror** them to Gitea immediately > 3. **Continue syncing** at the configured interval > 4. **Auto-discover** new repositories > 5. **Clean up** deleted repositories (if configured) > > This eliminates the need for manual button clicks - perfect for Docker/Kubernetes deployments! > **⏰ Scheduling with Cron Expressions** > Use cron expressions in `SCHEDULE_INTERVAL` to run at specific times: > - `"0 2 * * *"` - Daily at 2 AM > - `"0 */6 * * *"` - Every 6 hours > - `"0 0 * * 0"` - Weekly on Sunday at midnight > - `"0 3 * * 1-5"` - Weekdays at 3 AM (Monday-Friday) > > This is useful for optimizing bandwidth usage during low-activity periods. ### Execution Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `SCHEDULE_CONCURRENT` | Allow concurrent mirror operations | `false` | `true`, `false` | | `SCHEDULE_BATCH_SIZE` | Number of repos to process in parallel | `10` | Number | | `SCHEDULE_PAUSE_BETWEEN_BATCHES` | Pause between batches (milliseconds) | `5000` | Number | ### Retry Configuration | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `SCHEDULE_RETRY_ATTEMPTS` | Number of retry attempts | `3` | Number | | `SCHEDULE_RETRY_DELAY` | Delay between retries (milliseconds) | `60000` | Number | | `SCHEDULE_TIMEOUT` | Max time for a mirror operation (milliseconds) | `3600000` | Number | | `SCHEDULE_AUTO_RETRY` | Automatically retry failed operations | `true` | `true`, `false` | ### Update Detection | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `AUTO_IMPORT_REPOS` | Automatically discover and import new GitHub repositories during scheduled syncs | `true` | `true`, `false` | | `AUTO_MIRROR_REPOS` | Automatically mirror newly imported repositories during scheduled syncs (no manual “Mirror All” required) | `false` | `true`, `false` | | `SCHEDULE_ONLY_MIRROR_UPDATED` | Only mirror repos with updates | `false` | `true`, `false` | | `SCHEDULE_UPDATE_INTERVAL` | Check for updates interval (milliseconds) | `86400000` | Number | | `SCHEDULE_SKIP_RECENTLY_MIRRORED` | Skip recently mirrored repos | `true` | `true`, `false` | | `SCHEDULE_RECENT_THRESHOLD` | Skip if mirrored within this time (milliseconds) | `3600000` | Number | ### Maintenance & Notifications | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `SCHEDULE_CLEANUP_BEFORE_MIRROR` | Run cleanup before mirroring | `false` | `true`, `false` | | `SCHEDULE_NOTIFY_ON_FAILURE` | Send notifications on failure | `true` | `true`, `false` | | `SCHEDULE_NOTIFY_ON_SUCCESS` | Send notifications on success | `false` | `true`, `false` | | `SCHEDULE_LOG_LEVEL` | Logging level | `info` | `error`, `warn`, `info`, `debug` | | `SCHEDULE_TIMEZONE` | Timezone for scheduling | `UTC` | Valid timezone string | ## Database Cleanup Configuration Configure automatic cleanup of old events and data. ### Basic Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `CLEANUP_ENABLED` | Enable automatic cleanup | `false` | `true`, `false` | | `CLEANUP_RETENTION_DAYS` | Days to keep events | `7` | Number | ### Repository Cleanup | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `CLEANUP_DELETE_FROM_GITEA` | Apply the orphaned-repo action on the Gitea side too. When `false` (default), cleanup only updates gitea-mirror's own database (orphans are marked archived or removed from the repo list) and the Gitea/Forgejo copies are left untouched | `false` | `true`, `false` | | `CLEANUP_DELETE_IF_NOT_IN_GITHUB` | Delete repos not found in GitHub (automatically enables cleanup) | `true` | `true`, `false` | | `CLEANUP_ORPHANED_REPO_ACTION` | Action for orphaned repositories. **Note**: `archive` is recommended to preserve backups | `archive` | `skip`, `archive`, `delete` | | `CLEANUP_DRY_RUN` | Test mode without actual deletion | `false` | `true`, `false` | | `CLEANUP_PROTECTED_REPOS` | Comma-separated list of protected repository names | - | Comma-separated strings | **🛡️ Safety Features (Backup Protection)**: - **GitHub Failures Don't Delete Backups**: Cleanup is automatically skipped if GitHub API returns errors (404, 403, connection issues) - **Archive Never Deletes**: The `archive` action ALWAYS preserves repository data, it never deletes - **Graceful Degradation**: If marking as archived fails, the repository remains fully accessible in Gitea - **The Purpose of Backups**: Your mirrors are preserved even when GitHub sources disappear - that's the whole point! **Archive Behavior (Aligned with Gitea API)**: - **Regular repositories**: Uses Gitea's native archive feature (PATCH `/repos/{owner}/{repo}` with `archived: true`) - Makes repository read-only while preserving all data - **Mirror repositories**: Uses rename strategy (Gitea API returns 422 for archiving mirrors) - Renamed with `archived-` prefix for clear identification - Description updated with preservation notice and timestamp - Mirror interval set to 8760h (1 year) to minimize sync attempts - Repository remains fully accessible and cloneable - **Manual Sync Option**: Archived mirrors are still available on the Repositories page with automatic syncs disabled—use the `Manual Sync` action to refresh them on demand. ### Execution Settings | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `CLEANUP_BATCH_SIZE` | Number of items to process per batch | `10` | Number | | `CLEANUP_PAUSE_BETWEEN_DELETES` | Pause between deletions (milliseconds) | `2000` | Number | ## Authentication Configuration Configure authentication methods and SSO. ### Login Page | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `AUTH_DEFAULT_METHOD` | Tab the login page opens on when both email and SSO are available. Any other value falls back to `email`. | `email` | `email`, `sso` | | `AUTH_ALLOW_SIGNUP` | Allow email and password sign-up after the first account exists. Off, the sign-up endpoint answers 403 once a user exists; the first account can always be created. | `false` | `true`, `false` | The login page also remembers the method last used in that browser, which wins over this default. Anything unrecognised falls back to `email`. ### Header Authentication (Reverse Proxy SSO) | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `HEADER_AUTH_ENABLED` | Enable header-based authentication | `false` | `true`, `false` | | `HEADER_AUTH_USER_HEADER` | Header containing username | `X-Authentik-Username` | Header name | | `HEADER_AUTH_EMAIL_HEADER` | Header containing email | `X-Authentik-Email` | Header name | | `HEADER_AUTH_NAME_HEADER` | Header containing display name | `X-Authentik-Name` | Header name | | `HEADER_AUTH_AUTO_PROVISION` | Auto-create users from headers | `false` | `true`, `false` | | `HEADER_AUTH_ALLOWED_DOMAINS` | Comma-separated list of allowed email domains | - | Comma-separated domains | ## Docker Configuration Settings specific to Docker deployments. | Variable | Description | Default | Options | |----------|-------------|---------|---------| | `DOCKER_REGISTRY` | Docker registry URL | `ghcr.io` | Registry URL | | `DOCKER_IMAGE` | Docker image name | `raylabshq/gitea-mirror:` | Image name | | `DOCKER_TAG` | Docker image tag | `latest` | Tag name | ## Example Docker Compose Configuration Here's an example of how to use these environment variables in a `docker-compose.yml` file: ```yaml version: '3.8' services: gitea-mirror: image: ghcr.io/raylabshq/gitea-mirror:latest container_name: gitea-mirror environment: # Core Configuration - NODE_ENV=production - BASE_URL=/ - DATABASE_URL=file:data/gitea-mirror.db - BETTER_AUTH_SECRET=your-secure-secret-here # Primary access URL: - BETTER_AUTH_URL=https://gitea-mirror.mydomain.tld # Additional access URLs (local network + SSO providers): # - BETTER_AUTH_TRUSTED_ORIGINS=http://10.10.20.45:4321,http://192.168.1.100:4321,https://auth.provider.com # GitHub Configuration - GITHUB_USERNAME=your-username - GITHUB_TOKEN=ghp_your_token_here - PRIVATE_REPOSITORIES=true - MIRROR_STARRED=true - SKIP_FORKS=false # Gitea Configuration - GITEA_URL=http://gitea:3000 - GITEA_USERNAME=admin - GITEA_TOKEN=your-gitea-token - GITEA_ORGANIZATION=github-mirrors - GITEA_ORG_VISIBILITY=public # Mirror Options - MIRROR_RELEASES=true - MIRROR_WIKI=true - MIRROR_METADATA=true - MIRROR_ISSUES=true - MIRROR_PULL_REQUESTS=true # Automation - SCHEDULE_ENABLED=true - SCHEDULE_INTERVAL=3600 # Cleanup - CLEANUP_ENABLED=true - CLEANUP_RETENTION_DAYS=30 volumes: - ./data:/app/data ports: - "4321:4321" ``` ## Authentication URL Configuration ### Multiple Access URLs To allow access to Gitea Mirror through multiple URLs (e.g., local IP and public domain), you need to configure both server and client settings: **Example Configuration:** ```bash # Primary URL (required) - where the auth server is hosted BETTER_AUTH_URL=https://gitea-mirror.mydomain.tld # Client-side URL (optional) - tells the browser where to send auth requests # Set this to your primary domain when accessing from different origins PUBLIC_BETTER_AUTH_URL=https://gitea-mirror.mydomain.tld # Additional trusted origins (optional) - origins allowed to make auth requests BETTER_AUTH_TRUSTED_ORIGINS=http://10.10.20.45:4321,http://192.168.1.100:4321 ``` This setup allows you to: - Access via local network IP: `http://10.10.20.45:4321` - Access via public domain: `https://gitea-mirror.mydomain.tld` - Auth requests from the IP will be sent to the domain (via `PUBLIC_BETTER_AUTH_URL`) - Each origin requires separate login due to browser cookie isolation **Important:** When accessing from different origins (IP vs domain), you'll need to log in separately on each origin as cookies cannot be shared across different origins for security reasons. ### Path Prefix Deployments If you serve Gitea Mirror under a subpath such as `https://git.example.com/mirror`, set: ```bash # BASE_URL handles the path prefix — auth URLs stay as origin only BASE_URL=/mirror BETTER_AUTH_URL=https://git.example.com PUBLIC_BETTER_AUTH_URL=https://git.example.com BETTER_AUTH_TRUSTED_ORIGINS=https://git.example.com # → Auth endpoints resolve to: https://git.example.com/mirror/api/auth/* ``` Notes: - `BETTER_AUTH_URL` and `PUBLIC_BETTER_AUTH_URL` must be **origin only** (scheme + host). Do not include the base path — it is applied automatically from `BASE_URL`. Any path accidentally included is stripped. - `BETTER_AUTH_TRUSTED_ORIGINS` must also contain origins only (no path). - `BASE_URL` is applied at runtime, so prebuilt images can be reused with different path prefixes. ### Trusted Origins The `BETTER_AUTH_TRUSTED_ORIGINS` variable serves multiple purposes: 1. **SSO/OIDC Providers**: When using external authentication providers (Google, Authentik, Okta) 2. **Reverse Proxies**: When running behind nginx, Traefik, or other proxies 3. **Cross-Origin Requests**: When the frontend and backend are on different domains 4. **Development**: When testing from different URLs **Example Scenarios:** ```bash # For Authentik SSO integration BETTER_AUTH_TRUSTED_ORIGINS=https://authentik.company.com,https://auth.company.com # For reverse proxy setup BETTER_AUTH_TRUSTED_ORIGINS=https://proxy.internal,https://public.domain.com # For development with multiple environments BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:3000,http://192.168.1.100:3000 ``` **Important Notes:** - All URLs from `BETTER_AUTH_URL` are automatically trusted - URLs must be complete with protocol (http/https) - Multiple origins are separated by commas - No trailing slashes needed ## Notes 1. **First Run**: Environment variables are loaded when the container starts. The configuration is applied after the first user account is created. 2. **UI Priority**: Manual changes made through the web UI will be preserved. Environment variables only set values for empty fields. 3. **Token Security**: All tokens are encrypted before being stored in the database. 4. **Auto-Enabling Features**: Certain environment variables automatically enable features when set: - `GITEA_MIRROR_INTERVAL` - Automatically enables scheduled mirroring - `CLEANUP_DELETE_IF_NOT_IN_GITHUB=true` - Automatically enables repository cleanup - `SCHEDULE_INTERVAL` or `DELAY` - Automatically enables the scheduler 5. **Backward Compatibility**: The `DELAY` variable is maintained for backward compatibility but `SCHEDULE_INTERVAL` is preferred. 6. **Required Scopes**: The GitHub token requires the following scopes: - `repo` (full control of private repositories) - `admin:org` (read organization data) - Additional scopes may be required for specific features For more examples and detailed configuration, see the `.env.example` file in the repository.