forgejo/docs
31
58
Fork
You've already forked docs
249

storage migration process is undocumented #1178

Open
opened 2025年05月01日 23:12:29 +02:00 by infinoid · 9 comments
Contributor
Copy link

Hi,

The forgejo migrate-storage command has a --help listing in the Forgejo CLI page, but no real documentation on how to use it. The Storage settings describes how to configure the [storage] section, but not how to move existing data when updating the [storage] section.

I did a storage migration today, and I think some docs would have made it a bit smoother. Fortunately, I've been through this process with gitea once previously, so I was able to get through it again. But I would have loved some step-by-step instructions and examples.

As a potential starting point for that, I will describe what I did:

  1. made the decision to move local storage to minio/s3
  2. took stock of what was currently in local storage (for me, it's all packages, actions_log, and a few avatars)
  3. created a forgejo bucket, a user that has access to it, and an access key/secret key
  4. added a commented-out [storage] section with STORAGE_TYPE = minio and the necessary minio settings, to my config file
  5. shelled into the forgejo container, looked at the forgejo migrate-storage --help output
  6. mapped those settings to the corresponding parameters, with the help of the "Storage settings" page
  7. ran a shell loop to migrate each data type to s3
  8. uncommented the [storage] section of the config, restarted forgejo
  9. verified that packages, avatars, etc are still available

It took me some trial and error to get the right command for step 7. Here's what I ended up with:

for STORAGETYPE in attachments lfs avatars repo-avatars repo-archivers packages actions-log actions-artifacts; do
 forgejo migrate-storage --storage=minio [bucket, endpoint, ssl, key settings] --type=$STORAGETYPE --minio-base-path=$STORAGETYPE/
done

And here are the places I stumbled, along the way:

  1. I needed to add --user=git to my docker exec forgejo bash command, because it doesn't like to run as the root user.
  2. I assumed (incorrectly) that omitting the --type value would cause it to migrate EVERY type. It did not; it instead gave me an unclear error message Command error: unsupported storage:, which made me wonder if my s3-compatible server was not actually s3-compatible.
  3. I briefly hoped that the --type value would accept a comma-separated list of types. It did not.
  4. I assumed (incorrectly) that forgejo migrate-storage command would apply the same path prefixes that the [storage] configuration section would... meaning packages go under packages/, avatars under avatars/, etc. It did not. Instead, everything went to the root of the bucket, in a jumbled mess. I had to remove it all and start over with specified base paths.

In the end, it all worked. But is this the intended usage? It took me a while to get there.

Thanks!

Hi, The `forgejo migrate-storage` command has a `--help` listing in [the Forgejo CLI page](https://forgejo.org/docs/latest/admin/command-line/#migrate-storage), but no real documentation on how to use it. The [Storage settings](https://forgejo.org/docs/latest/admin/storage/) describes how to configure the `[storage]` section, but not how to move existing data when updating the `[storage]` section. I did a storage migration today, and I think some docs would have made it a bit smoother. Fortunately, I've been through this process with gitea once previously, so I was able to get through it again. But I would have loved some step-by-step instructions and examples. As a potential starting point for that, I will describe what I did: 1. made the decision to move local storage to minio/s3 2. took stock of what was currently in local storage (for me, it's all packages, actions_log, and a few avatars) 3. created a forgejo bucket, a user that has access to it, and an access key/secret key 4. added a commented-out `[storage]` section with `STORAGE_TYPE = minio` and the necessary minio settings, to my config file 5. shelled into the forgejo container, looked at the `forgejo migrate-storage --help` output 6. mapped those settings to the corresponding parameters, with the help of the "Storage settings" page 7. ran a shell loop to migrate each data type to s3 8. uncommented the `[storage]` section of the config, restarted forgejo 9. verified that packages, avatars, etc are still available It took me some trial and error to get the right command for step 7. Here's what I ended up with: ```shell for STORAGETYPE in attachments lfs avatars repo-avatars repo-archivers packages actions-log actions-artifacts; do forgejo migrate-storage --storage=minio [bucket, endpoint, ssl, key settings] --type=$STORAGETYPE --minio-base-path=$STORAGETYPE/ done ``` And here are the places I stumbled, along the way: 1. I needed to add `--user=git` to my `docker exec forgejo bash` command, because it doesn't like to run as the root user. 2. I assumed (incorrectly) that omitting the `--type` value would cause it to migrate *EVERY* type. It did not; it instead gave me an unclear error message `Command error: unsupported storage:`, which made me wonder if my s3-compatible server was not actually s3-compatible. 3. I briefly hoped that the `--type` value would accept a comma-separated list of types. It did not. 4. I assumed (incorrectly) that `forgejo migrate-storage` command would apply the same path prefixes that the `[storage]` configuration section would... meaning packages go under `packages/`, avatars under `avatars/`, etc. It did not. Instead, everything went to the root of the bucket, in a jumbled mess. I had to remove it all and start over with specified base paths. In the end, it all worked. But is this the intended usage? It took me a while to get there. Thanks!
Author
Contributor
Copy link

The next day, I noticed that the old action logs were in actions-log (with a hyphen), but newly created logs were in actions_log (with an underscore), and the UI couldn't access the old logs. So I had migrated them to the wrong target location, and had to move them into place manually.

Oops.

For posterity, the command I used to move them was

AWS_PROFILE=cephs3 aws s3 mv --recursive s3://forgejo/actions-log/infinoid s3://forgejo/actions_log/infinoid/

That seemed to do the right thing, and now I can see older logs in forgejo's action tab again.

The next day, I noticed that the old action logs were in `actions-log` (with a hyphen), but newly created logs were in `actions_log` (with an underscore), and the UI couldn't access the old logs. So I had migrated them to the wrong target location, and had to move them into place manually. Oops. For posterity, the command I used to move them was ```shell AWS_PROFILE=cephs3 aws s3 mv --recursive s3://forgejo/actions-log/infinoid s3://forgejo/actions_log/infinoid/ ``` That seemed to do the right thing, and now I can see older logs in forgejo's action tab again.
Member
Copy link

Hi, glad you solved this issue! Do you have any ideas as to how the documentation could be updated so as to prevent such an error or similar errors from taking place? (either through better instructions or by using an explicit warning?)

Hi, glad you solved this issue! Do you have any ideas as to how the documentation could be updated so as to prevent such an error or similar errors from taking place? (either through better instructions or by using an explicit warning?)
Author
Contributor
Copy link

Would it make sense to fix up and use my list of steps as an example? It would cover the local→minio case, at least.

Would it make sense to fix up and use my list of steps as an example? It would cover the local→minio case, at least.

This really should be documented. Ideally the migration tooling should respect the app.ini configuration.

This really should be documented. Ideally the migration tooling should respect the app.ini configuration.
Author
Contributor
Copy link

Ideally the migration tooling should respect the app.ini configuration.

I think the migrate-storage command is essentially a copy operation. The app.ini configuration is the "from" location, and the command-line parameters are the "to" location. So it does respect it? Kinda?

> Ideally the migration tooling should respect the app.ini configuration. I think the migrate-storage command is essentially a copy operation. The `app.ini` configuration is the "from" location, and the command-line parameters are the "to" location. So it does respect it? Kinda?
Author
Contributor
Copy link

Although... I think passing it an old_app.ini and new_app.ini would have made the process much clearer.

This would have prevented my confusion I had over things like the "lfs/" suffix on the LFS folder, and the fact that the hyphen in the "--actions-log" parameter doesn't match the underscore in the "actions_log/" suffix.

If the config files don't change the default, then the suffix stays the same, and everything just works. And even if it does change, the copy target will match the runtime location when I install the new config file, and everything just works.

I know this bug is about documentation, sorry...

Although... I think passing it an `old_app.ini` and `new_app.ini` would have made the process much clearer. This would have prevented my confusion I had over things like the "lfs/" suffix on the LFS folder, and the fact that the hyphen in the "--actions-log" parameter doesn't match the underscore in the "actions_log/" suffix. If the config files don't change the default, then the suffix stays the same, and everything just works. And even if it does change, the copy target will match the runtime location when I install the new config file, and everything just works. I know this bug is about documentation, sorry...

@infinoid wrote in #1178 (comment):

Ideally the migration tooling should respect the app.ini configuration.

I think the migrate-storage command is essentially a copy operation. The app.ini configuration is the "from" location, and the command-line parameters are the "to" location. So it does respect it? Kinda?

I'm not sure, it looks like everything copied over but when I enable FORGEJO__STORAGE__STORAGE_TYPE=minio it's returning 404 for assets.

Edit: It looks like it's just the path prefixes like you mentioned above.

@infinoid wrote in https://codeberg.org/forgejo/docs/issues/1178#issuecomment-4622789: > > Ideally the migration tooling should respect the app.ini configuration. > > I think the migrate-storage command is essentially a copy operation. The `app.ini` configuration is the "from" location, and the command-line parameters are the "to" location. So it does respect it? Kinda? I'm not sure, it looks like everything copied over but when I enable `FORGEJO__STORAGE__STORAGE_TYPE=minio` it's returning 404 for assets. Edit: It looks like it's just the path prefixes like you mentioned above.

@infinoid wrote in #1178 (comment):

Although... I think passing it an old_app.ini and new_app.ini would have made the process much clearer.

I think adding a second configuration file will just add extra steps that aren't needed.

I think it should just be documented and the path prefixes respected.

Then it's just a simple bash command to migrate and then change the storage type from local to minio. I didn't realize it had to be in local setup either for the migration.

Edit: I would also document that the old data needs to be manually cleared out after verifying that the migration was successful.

@infinoid wrote in https://codeberg.org/forgejo/docs/issues/1178#issuecomment-4622885: > Although... I think passing it an `old_app.ini` and `new_app.ini` would have made the process much clearer. I think adding a second configuration file will just add extra steps that aren't needed. I think it should just be documented and the path prefixes respected. Then it's just a simple bash command to migrate and then change the storage type from local to minio. I didn't realize it had to be in local setup either for the migration. Edit: I would also document that the old data needs to be manually cleared out after verifying that the migration was successful.

I spent a few hours figuring out the migration process. Thankfully this thread helped me understand the process.

I've documented the steps here to help others. In my case I used RustFS

Guide: Migrating Forgejo Local Storage to S3/MinIO

1. Prerequisites

  • Ensure your Forgejo container is running.
  • Log into your Forgejo container as the git user.
  • Backup your database and data volumes before proceeding.

2. Identify Storage Types and Paths

First, login to your container and run the help command to see supported storage types:

forgejo migrate-storage -h

Current supported types: attachments, lfs, avatars, repo-avatars, repo-archivers, packages, actions-log, actions-artifacts.

Locate your local data paths. In a standard Docker setup, these usually reside under /data/gitea/ or /data/git/.

Example:

/data/gitea/attachments/
/data/gitea/avatars/
/data/gitea/repo-avatars/
/data/gitea/repo-archivers/
/data/gitea/packages/
/data/gitea/actions-log/
/data/gitea/actions-artifacts/
/data/git/lfs/

3. Migration Commands

Replace the placeholders (<...>) with your specific storage configuration.

Step A: Migrate LFS (if stored in a custom location)

forgejo migrate-storage \
 --type=lfs \
 --storage=minio \
 --minio-endpoint=<STORAGE_URL> \
 --minio-access-key-id=<ACCESS_KEY> \
 --minio-secret-access-key=<SECRET_KEY> \
 --minio-bucket=<BUCKET_NAME> \
 --path=/data/git/lfs \
 --minio-base-path=lfs/ \
 --minio-use-ssl=true

Step B: Migrate Remaining Storage Types

for DATATYPE in attachments avatars repo-avatars repo-archivers packages actions-log actions-artifacts; do
 echo "Migrating $DATATYPE..."
 forgejo migrate-storage \
 --type=$DATATYPE \
 --storage=minio \
 --minio-endpoint=<STORAGE_URL> \
 --minio-access-key-id=<ACCESS_KEY> \
 --minio-secret-access-key=<SECRET_KEY> \
 --minio-bucket=<BUCKET_NAME> \
 --path=/data/gitea/$DATATYPE/ \
 --minio-base-path=$DATATYPE/ \
 --minio-use-ssl=true
done

Note: Verify that your files have successfully appeared in your S3 bucket before proceeding.

4. Update Configuration (app.ini)

Open /data/gitea/conf/app.ini and add the global storage configuration:

[storage]
STORAGE_TYPE = minio
MINIO_USE_SSL = true
MINIO_ENDPOINT = <STORAGE_URL>
MINIO_ACCESS_KEY_ID = <ACCESS_KEY>
MINIO_SECRET_ACCESS_KEY = <SECRET_KEY>
MINIO_BUCKET = <BUCKET_NAME>
MINIO_LOCATION = us-east-1

Next, remove the local storage path definitions from their respective sections.

Remove these lines as applicable:

Note: If a section only contained the path variable, you can remove the section entirely.

[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
[attachment]
PATH = /data/gitea/attachments
[lfs]
PATH = /data/git/lfs

5. Restart and Cleanup

Restart your container to apply the changes:

docker compose up -d forgejo --force-recreate

Once you have verified that Forgejo is serving files correctly from S3, you can safely clear your local storage:
Login to the container again and run the below commands.

rm -rf /data/gitea/attachments/*
rm -rf /data/gitea/avatars/*
rm -rf /data/gitea/repo-avatars/*
rm -rf /data/gitea/repo-archivers/*
rm -rf /data/gitea/packages/*
rm -rf /data/gitea/actions-log/*
rm -rf /data/gitea/actions-artifacts/*
rm -rf /data/git/lfs/*
I spent a few hours figuring out the migration process. Thankfully this thread helped me understand the process. I've documented the steps here to help others. In my case I used [RustFS](https://github.com/rustfs/rustfs) ### Guide: Migrating Forgejo Local Storage to S3/MinIO #### 1. Prerequisites * Ensure your Forgejo container is running. * Log into your Forgejo container as the `git` user. * **Backup your database and data volumes** before proceeding. #### 2. Identify Storage Types and Paths First, login to your container and run the help command to see supported storage types: ```bash forgejo migrate-storage -h ``` *Current supported types: `attachments`, `lfs`, `avatars`, `repo-avatars`, `repo-archivers`, `packages`, `actions-log`, `actions-artifacts`.* Locate your local data paths. In a standard Docker setup, these usually reside under `/data/gitea/` or `/data/git/`. Example: ```md /data/gitea/attachments/ /data/gitea/avatars/ /data/gitea/repo-avatars/ /data/gitea/repo-archivers/ /data/gitea/packages/ /data/gitea/actions-log/ /data/gitea/actions-artifacts/ /data/git/lfs/ ``` #### 3. Migration Commands Replace the placeholders (`<...>`) with your specific storage configuration. **Step A: Migrate LFS (if stored in a custom location)** ```bash forgejo migrate-storage \ --type=lfs \ --storage=minio \ --minio-endpoint=<STORAGE_URL> \ --minio-access-key-id=<ACCESS_KEY> \ --minio-secret-access-key=<SECRET_KEY> \ --minio-bucket=<BUCKET_NAME> \ --path=/data/git/lfs \ --minio-base-path=lfs/ \ --minio-use-ssl=true ``` **Step B: Migrate Remaining Storage Types** ```bash for DATATYPE in attachments avatars repo-avatars repo-archivers packages actions-log actions-artifacts; do echo "Migrating $DATATYPE..." forgejo migrate-storage \ --type=$DATATYPE \ --storage=minio \ --minio-endpoint=<STORAGE_URL> \ --minio-access-key-id=<ACCESS_KEY> \ --minio-secret-access-key=<SECRET_KEY> \ --minio-bucket=<BUCKET_NAME> \ --path=/data/gitea/$DATATYPE/ \ --minio-base-path=$DATATYPE/ \ --minio-use-ssl=true done ``` *Note: Verify that your files have successfully appeared in your S3 bucket before proceeding.* #### 4. Update Configuration (`app.ini`) Open `/data/gitea/conf/app.ini` and add the global storage configuration: ```ini [storage] STORAGE_TYPE = minio MINIO_USE_SSL = true MINIO_ENDPOINT = <STORAGE_URL> MINIO_ACCESS_KEY_ID = <ACCESS_KEY> MINIO_SECRET_ACCESS_KEY = <SECRET_KEY> MINIO_BUCKET = <BUCKET_NAME> MINIO_LOCATION = us-east-1 ``` Next, remove the local storage path definitions from their respective sections. **Remove these lines as applicable:** *Note: If a section only contained the path variable, you can remove the section entirely.* ```ini [picture] AVATAR_UPLOAD_PATH = /data/gitea/avatars REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars [attachment] PATH = /data/gitea/attachments [lfs] PATH = /data/git/lfs ``` #### 5. Restart and Cleanup Restart your container to apply the changes: ```bash docker compose up -d forgejo --force-recreate ``` Once you have verified that Forgejo is serving files correctly from S3, you can safely clear your local storage: Login to the container again and run the below commands. ```bash rm -rf /data/gitea/attachments/* rm -rf /data/gitea/avatars/* rm -rf /data/gitea/repo-avatars/* rm -rf /data/gitea/repo-archivers/* rm -rf /data/gitea/packages/* rm -rf /data/gitea/actions-log/* rm -rf /data/gitea/actions-artifacts/* rm -rf /data/git/lfs/* ```
Sign in to join this conversation.
No Branch/Tag specified
next
v16.0
v15.0
v11.0
bp-v15.0-c7697f2
actions-remove-non-existing-strategy-options
v14.0
v13.0
v12.0
v7.0
v10.0
v9.0
v8.0
v1.21
v1.20
v1.19
v13.0.0-dev
Labels
Clear labels
404
Broken links or missing content
backport/v1.19
Changes which should be backported to the v1.19 docs

Archived

backport/v1.20
Changes which should be backported to the v1.20 docs

Archived

backport/v1.21
Changes which should be backported to the v1.21 docs

Archived

backport/v10.0
Automated backport to v10.0

Archived

backport/v11.0
Automated backport to v11.0
backport/v12.0
Automated backport to v12.0

Archived

backport/v13.0
Automated backport to v13.0

Archived

backport/v14.0
Automated backport to v14.0

Archived

backport/v15.0
Automated backport to v15.0
backport/v16.0
Automated backport to v16.0
backport/v7.0
Automated backport to the v7.0 docs

Archived

backport/v8.0
Automated backport to the v8.0 docs

Archived

backport/v9.0
Automated backport to the v9.0 docs

Archived

good first issue
This issue is suitable for "drive-by contributors" wanting to contribute for the first time, and fixing it should be straightforward.
meta
Tooling and processes for maintaining the docs
new docs
Content to be added to the documentation

Archived

User research - Accessibility
Requires input about accessibility features, likely involves user testing.
User research - Blocked
Do not pick as-is! We are happy if you can help, but please coordinate with ongoing redesign in this area.
User research - Community
Community features, such as discovering other people's work or otherwise feeling welcome on a Forgejo instance.
User research - Config (instance)
Instance-wide configuration, authentication and other admin-only needs.
User research - Errors
How to deal with errors in the application and write helpful error messages.
User research - Filters
How filter and search is being worked with.
User research - Future backlog
The issue might be inspiring for future design work.
User research - Git workflow
AGit, fork-based and new Git workflow, PR creation etc
User research - Labels
Active research about Labels
User research - Moderation
Moderation Featuers for Admins are undergoing active User Research
User research - Needs input
Use this label to let the User Research team know their input is requested.
User research - Notifications/Dashboard
Research on how users should know what to do next.
User research - Rendering
Text rendering, markup languages etc
User research - Repo creation
Active research about the New Repo dialog.
User research - Repo units
The repo sections, disabling them and the "Add more" button.
User research - Security
User research - Settings (in-app)
How to structure in-app settings in the future?
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo/docs#1178
Reference in a new issue
forgejo/docs
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?