# Gitea on Dokploy Self-hosted Gitea deployment running on Dokploy with a local Postgres database. - **Domain**: `gitea.routinedevelopment.ca` - **SSH**: Port 2222 (built-in SSH server, HTTP git disabled) - **Database**: Local Postgres 16 (container `gitea-db`) - **Volumes**: `gitea-data` (repos, LFS, avatars, SSH keys), `db-data` (Postgres) ## Setup (Fresh Install) 1. Install Dokploy on a clean Ubuntu server: ```bash curl -sSL https://dokploy.com/install.sh | sh ``` 2. Create a new Project in Dokploy called "Gitea". 3. Create a Docker Compose service inside the project. Paste the contents of `docker-compose.yml`. 4. Add the environment variable in Dokploy's UI: ``` POSTGRES_PASSWORD=your_strong_password ``` 5. Deploy. Let it complete the first boot. 6. Point your DNS A record for `gitea.routinedevelopment.ca` to the server IP. 7. In Dokploy's UI, go to the Gitea compose service → **Domains** tab. Add `gitea.routinedevelopment.ca` with container port `3000`, HTTPS enabled, and Let's Encrypt certificate. The docs say Traefik labels alone should work, but in practice you may need to also add the domain via the UI. 8. Redeploy so Traefik picks up the domain and issues the Let's Encrypt certificate. ### Domain Troubleshooting If the domain doesn't work after deploying: - **DNS must resolve first**: Let's Encrypt needs to reach the server. Make sure your DNS/reserved IP points to the server *before* adding the domain in Dokploy. If added too early, recreate the domain or restart Traefik. - **`dokploy-network` is required**: Traefik runs on `dokploy-network`. If your compose service isn't on that network, Traefik can't reach it even if the labels are correct. The compose file in this repo already handles this. - **Reserved IP mismatch**: If using a DigitalOcean reserved IP, Dokploy may complain that the domain resolves to the reserved IP instead of the droplet's direct IP. This is fine — traffic still reaches the server. Deploy anyway. - **Redeploy after any domain change**: Unlike Applications, Docker Compose services require a redeploy for domain changes to take effect. ## Restore from Backup If restoring onto a fresh Dokploy instance after the initial deploy: 1. SCP the backup files to the server: ```bash scp gitea_db_backup.dump user@server:~/ scp gitea_files_backup.tar.gz user@server:~/ scp app.ini user@server:~/ # the REAL one with secrets, not the template ``` 2. SSH into the server and run the restore script: ```bash chmod +x restore.sh ./restore.sh ``` 3. Verify at `https://gitea.routinedevelopment.ca` — all repos, users, and orgs should be present. ## Backup Run from the Dokploy server: ```bash chmod +x backup.sh ./backup.sh ``` Backups are saved to `~/gitea-backups/` with timestamps. Each backup creates three files: - `gitea_db_YYYYMMDD_HHMMSS.dump` — Postgres database dump - `gitea_files_YYYYMMDD_HHMMSS.tar.gz` — Repositories, LFS, avatars, attachments, SSH keys - `app_YYYYMMDD_HHMMSS.ini` — Current app.ini config (contains secrets) You can specify a custom backup directory: ```bash ./backup.sh /path/to/backups ``` **Recommended**: Push backups offsite (S3, DigitalOcean Spaces, etc.). Don't rely solely on the same disk. ## Automated Backups (Optional) Add a cron job on the server to run backups daily: ```bash crontab -e ``` ``` 0 3 * * * /path/to/backup.sh /home/user/gitea-backups >> /var/log/gitea-backup.log 2>&1 ``` ## Secrets The `app.ini` in this repo has `` placeholders. The real values you need to set: | Key | Location | Description | |-----|----------|-------------| | `LFS_JWT_SECRET` | `[server]` | JWT secret for LFS | | `INTERNAL_TOKEN` | `[security]` | Internal API token | | `JWT_SECRET` | `[oauth2]` | OAuth2 JWT secret | | `PASSWD` | `[database]` | Must match `POSTGRES_PASSWORD` env var | Keep your real `app.ini` as `app.ini.local` (gitignored) or in a password manager. ## SSH Remotes Since HTTP git is disabled, all clones use SSH on port 2222: ```bash git clone ssh://git@gitea.routinedevelopment.ca:2222/org/repo.git ``` Note: The container user is `git`, not `gitea`. If migrating from baremetal, update your remotes: ```bash git remote set-url origin ssh://git@gitea.routinedevelopment.ca:2222/YourOrg/your-repo.git ``` ## GitHub Mirror To push-mirror a repo to GitHub: 1. Ensure the container has an SSH key: ```bash docker exec gitea ls /data/git/.ssh/id_ed25519.pub ``` If not, generate one: ```bash docker exec gitea ssh-keygen -t ed25519 -f /data/git/.ssh/id_ed25519 -N "" docker exec gitea chown git:git /data/git/.ssh/id_ed25519 ``` 2. Add the public key as a deploy key (with write access) on your GitHub repo. 3. Set up a post-receive hook or cron to push. The SSH key lives in the `gitea-data` volume and persists across redeploys. ## Volume Info | Volume | Contents | Path in container | |--------|----------|-------------------| | `gitea-data` | Repos, LFS, avatars, config, SSH keys | `/data` | | `db-data` | Postgres data | `/var/lib/postgresql/data` | Volumes persist across redeploys. They are only destroyed by `docker compose down -v` or `docker volume rm`. **Never run `down -v` in production.** Inspect volumes: ```bash docker volume ls | grep gitea docker volume inspect ```