> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/go-gitea/gitea/llms.txt
> Use this file to discover all available pages before exploring further.

# Backup and Restore

> Back up and restore Gitea data and repositories

## Overview

Gitea provides built-in commands for backing up and restoring your entire installation, including repositories, database, configuration, and attachments.

## Backup

The `dump` command creates a compressed archive containing all Gitea data.

### Basic Backup

```bash theme={null}
gitea dump
```

This creates a file named `gitea-dump-{timestamp}.zip` in the current directory.

### Specify Output File

```bash theme={null}
gitea dump --file my-backup.zip
```

### Backup to stdout

```bash theme={null}
gitea dump --file - > backup.zip
```

### Backup Options

The dump command supports extensive customization options (see `cmd/dump.go:27-97`):

<ParamField path="--file" type="string" default="gitea-dump-{time}.zip">
  Output file name. Use `-` for stdout.
</ParamField>

<ParamField path="--tempdir" type="string" default="system temp dir">
  Temporary directory for building the archive
</ParamField>

<ParamField path="--type" type="string" default="zip">
  Archive format: `zip`, `tar`, `tar.gz`, `tar.xz`, `tar.bz2`, `tar.lz4`, `tar.sz`, or `tar.zst`
</ParamField>

<ParamField path="--database" type="string">
  Database SQL syntax for export: `sqlite3`, `mysql`, `postgres`, `mssql`.
  Use this to export to a different database format than currently configured.
</ParamField>

<ParamField path="--verbose" type="boolean" default="false">
  Show detailed progress during backup
</ParamField>

<ParamField path="--quiet" type="boolean" default="false">
  Only show warnings and errors
</ParamField>

### Selective Backup

You can exclude specific components from the backup:

<CodeGroup>
  ```bash Skip Repositories theme={null}
  gitea dump --skip-repository
  ```

  ```bash Skip Database theme={null}
  gitea dump --skip-db
  ```

  ```bash Skip Logs theme={null}
  gitea dump --skip-log
  ```

  ```bash Skip Custom Directory theme={null}
  gitea dump --skip-custom-dir
  ```

  ```bash Skip LFS Data theme={null}
  gitea dump --skip-lfs-data
  ```

  ```bash Skip Attachments theme={null}
  gitea dump --skip-attachment-data
  ```

  ```bash Skip Packages theme={null}
  gitea dump --skip-package-data
  ```

  ```bash Skip Search Index theme={null}
  gitea dump --skip-index
  ```
</CodeGroup>

### Combine Multiple Options

```bash theme={null}
gitea dump \
  --file /backup/gitea-$(date +%Y%m%d).tar.gz \
  --type tar.gz \
  --tempdir /tmp/gitea-backup \
  --skip-log \
  --skip-index \
  --verbose
```

## What's Included in a Backup

A complete Gitea backup includes:

1. **Database** - All database tables and data
2. **Repositories** - Git repositories and their data
3. **Configuration** - `app.ini` configuration file
4. **Custom Files** - Templates, logos, and customizations
5. **Data Directory** - User avatars, attachments, etc.
6. **LFS Objects** - Git LFS files (if enabled)
7. **Attachments** - Issue and comment attachments
8. **Packages** - Package registry data (if enabled)
9. **Logs** - Application logs (optional)

The backup structure (from `cmd/dump.go:164-324`):

```text theme={null}
gitea-dump.zip
├── app.ini              # Configuration file
├── gitea-db.sql         # Database dump
├── repos/               # All repositories
├── custom/              # Custom templates and assets
├── data/
│   ├── lfs/            # LFS objects
│   ├── attachments/    # File attachments
│   ├── packages/       # Package data
│   └── ...             # Other app data
└── log/                # Log files (optional)
```

## Restore

Restoring from a backup involves extracting the archive and placing files in the correct locations.

### Complete Restore

<Steps>
  <Step title="Stop Gitea">
    ```bash theme={null}
    sudo systemctl stop gitea
    ```
  </Step>

  <Step title="Extract Backup">
    ```bash theme={null}
    unzip gitea-dump-1234567890.zip -d /tmp/gitea-restore
    ```
  </Step>

  <Step title="Restore Database">
    <CodeGroup>
      ```bash PostgreSQL theme={null}
      # Drop existing database
      sudo -u postgres psql -c "DROP DATABASE gitea;"
      sudo -u postgres psql -c "CREATE DATABASE gitea;"

      # Restore from backup
      sudo -u postgres psql gitea < /tmp/gitea-restore/gitea-db.sql
      ```

      ```bash MySQL theme={null}
      # Drop existing database
      mysql -u root -p -e "DROP DATABASE gitea;"
      mysql -u root -p -e "CREATE DATABASE gitea;"

      # Restore from backup
      mysql -u root -p gitea < /tmp/gitea-restore/gitea-db.sql
      ```

      ```bash SQLite theme={null}
      # Backup current database
      mv data/gitea.db data/gitea.db.old

      # Restore from backup
      cp /tmp/gitea-restore/gitea-db.sql data/gitea.db
      ```
    </CodeGroup>
  </Step>

  <Step title="Restore Files">
    ```bash theme={null}
    # Restore repositories
    rm -rf /path/to/gitea/data/gitea-repositories
    cp -r /tmp/gitea-restore/repos /path/to/gitea/data/gitea-repositories

    # Restore data directory
    cp -r /tmp/gitea-restore/data/* /path/to/gitea/data/

    # Restore custom directory (if present)
    cp -r /tmp/gitea-restore/custom/* /path/to/gitea/custom/

    # Restore configuration
    cp /tmp/gitea-restore/app.ini /path/to/gitea/custom/conf/app.ini
    ```
  </Step>

  <Step title="Fix Permissions">
    ```bash theme={null}
    sudo chown -R git:git /path/to/gitea/data
    sudo chown -R git:git /path/to/gitea/custom
    ```
  </Step>

  <Step title="Start Gitea">
    ```bash theme={null}
    sudo systemctl start gitea
    ```
  </Step>
</Steps>

## Repository-Level Restore

Restore a single repository using the `restore-repo` command (see `cmd/restore_repo.go`):

```bash theme={null}
gitea restore-repo \
  --repo_dir /path/to/backup/repos/owner/repo.git \
  --owner_name target-owner \
  --repo_name target-repo
```

### Selective Repository Restore

Restore specific repository components:

```bash theme={null}
gitea restore-repo \
  --repo_dir /backup/repos/owner/repo.git \
  --owner_name owner \
  --repo_name repo \
  --units "issues,labels,milestones,pull_requests,comments"
```

Available units:

* `wiki`
* `issues`
* `labels`
* `releases`
* `release_assets`
* `milestones`
* `pull_requests`
* `comments`

### Validation Before Restore

```bash theme={null}
gitea restore-repo \
  --repo_dir /backup/repos/owner/repo.git \
  --owner_name owner \
  --repo_name repo \
  --validation
```

This performs a sanity check on the backup data before attempting restoration.

## Automated Backup

Create a backup script for automated backups:

```bash backup.sh theme={null}
#!/bin/bash

# Configuration
BACKUP_DIR="/backup/gitea"
RETENTION_DAYS=30
DATESTAMP=$(date +%Y%m%d-%H%M%S)

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Run backup
/usr/local/bin/gitea dump \
  --file "$BACKUP_DIR/gitea-$DATESTAMP.zip" \
  --tempdir /tmp/gitea-backup \
  --skip-log \
  --verbose

# Check if backup succeeded
if [ $? -eq 0 ]; then
    echo "Backup completed successfully: gitea-$DATESTAMP.zip"

    # Remove old backups
    find "$BACKUP_DIR" -name "gitea-*.zip" -mtime +$RETENTION_DAYS -delete
    echo "Removed backups older than $RETENTION_DAYS days"
else
    echo "Backup failed!" >&2
    exit 1
fi
```

### Schedule with Cron

```cron theme={null}
# Daily backup at 2 AM
0 2 * * * /usr/local/bin/gitea-backup.sh >> /var/log/gitea-backup.log 2>&1
```

### Schedule with systemd Timer

Create `/etc/systemd/system/gitea-backup.service`:

```ini theme={null}
[Unit]
Description=Gitea Backup
After=network.target

[Service]
Type=oneshot
User=git
ExecStart=/usr/local/bin/gitea dump --file /backup/gitea/gitea-%Y%m%d.zip
```

Create `/etc/systemd/system/gitea-backup.timer`:

```ini theme={null}
[Unit]
Description=Gitea Backup Timer

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
```

Enable the timer:

```bash theme={null}
sudo systemctl enable gitea-backup.timer
sudo systemctl start gitea-backup.timer
```

## Database-Only Backup

For quick database backups without repositories:

<CodeGroup>
  ```bash PostgreSQL theme={null}
  pg_dump -h localhost -U gitea gitea > gitea-db-$(date +%Y%m%d).sql
  ```

  ```bash MySQL theme={null}
  mysqldump -u gitea -p gitea > gitea-db-$(date +%Y%m%d).sql
  ```

  ```bash SQLite theme={null}
  sqlite3 data/gitea.db ".backup gitea-db-$(date +%Y%m%d).db"
  ```
</CodeGroup>

## Disaster Recovery

### Backup Verification

Regularly verify your backups:

```bash theme={null}
# Extract to temporary location
unzip -t gitea-dump-20240101.zip

# Or restore to a test instance
```

### Off-Site Backup

Copy backups to remote storage:

```bash theme={null}
# Using rsync
rsync -avz /backup/gitea/ user@backup-server:/gitea-backups/

# Using rclone to cloud storage
rclone sync /backup/gitea/ remote:gitea-backups/
```

### Recovery Time Objective (RTO)

Plan for recovery:

1. **Database restore**: 5-30 minutes depending on size
2. **Repository restore**: Depends on repository count and size
3. **Configuration**: 1-5 minutes
4. **Total downtime**: Plan for 30-60 minutes for most installations

## Best Practices

* **Regular Backups**: Daily backups for production systems
* **Test Restores**: Regularly test your backup restoration process
* **Multiple Locations**: Store backups in multiple locations (on-site and off-site)
* **Encryption**: Encrypt backups containing sensitive data
* **Retention Policy**: Define how long to keep backups (e.g., 30 days)
* **Monitoring**: Alert on backup failures
* **Documentation**: Document your backup and restore procedures
* **Separate Database Backups**: Consider additional database-specific backups

## Troubleshooting

### Backup Fails with "Permission Denied"

```bash theme={null}
# Ensure Gitea has write access to backup directory
sudo chown git:git /backup/gitea
sudo chmod 755 /backup/gitea
```

### Backup File Too Large

```bash theme={null}
# Use compression
gitea dump --type tar.gz --file backup.tar.gz

# Or exclude large optional data
gitea dump --skip-log --skip-index
```

### Database Restore Fails

```bash theme={null}
# Check database encoding
# PostgreSQL: should be UTF8
# MySQL: should be utf8mb4

# Verify SQL file integrity
head -n 50 gitea-db.sql
```

## Related Resources

* [Configuration](/admin/configuration)
* [Database Setup](/admin/database)
* [Command-Line Tools](/admin/command-line)
