Post

ENG | Upgrading Forgejo 11 to Forgejo 15

ENG | Upgrading Forgejo 11 to Forgejo 15

Article needs polishing such as links, maybe images, diff of compose file. Task for tomorrow I guess…

Today I found that new Forgejo 15.0 LTS was released, but I’m running Forgejo 11.0.x I backed up container volumes (database, config, data) using years old script [TODO:LINK], run podman-compose -f ...yml pull, podman-compose -f ...yml up. There was something about database update. I tried. Then I tried to log in via web page and was greeted by Forgejo installation. Weird. I certainly messed up something. In retrospect there were several problems

  1. Database update needed some manual intervention
  2. Forgejo’s config file changed location
  3. Wrong file permissions that previously did not matter

Issue 1: Restoring state from backup and retry

Hopefully I have some instructions how to migrate Gitea to Forgejo, which have backup and restoration procedure for testing [TODO:LINK]

Maybe start with database and return to forgejo-11 - we want to isolate if this was database upgrade problem or Forgejo update problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
###################################################
# Stop running Forgejo server and database
podman-compose -f ~/docker/docker-compose-forgejo.yml stop
#gitea
#gitea-mariadb

####################################################
# Remove containers
$ podman ps -a
#CONTAINER ID  IMAGE                                           COMMAND               CREATED         STATUS                    PORTS                                           NAMES
#d53a1a86d4e8  lscr.io/linuxserver/mariadb:latest                                    40 minutes ago  Exited (0) 2 minutes ago  3306/tcp                                        gitea-mariadb
#c3f6d9311f6b  codeberg.org/forgejo/forgejo:15.0-rootless                            40 minutes ago  Exited (1) 2 minutes ago  0.0.0.0:2222->2222/tcp, 0.0.0.0:8082->3000/tcp  gitea
podman container rm d53a1a86d4e8
#Error: container d53a1a86d4e82c348dc9e3080e3bc5d2d7690843a6828a70085226c3c6563f5c has dependent containers which must be removed before it: c3f6d9311f6b4da0adf387854da2e13b965a03ce7cca51bce88165008f187212: container already exists
podman container rm c3f6d9311f6b
# c3f6d9311f6b
podman container rm d53a1a86d4e8
# d53a1a86d4e8

#############################################
# Remove and recreate volume, import data
podman volume remove docker_gitea-db
# docker_gitea-db
podman volume create docker_gitea-db
# docker_gitea-db
zstd -d < ~/backup/gitea-db-2026-04-21.tar.zst | podman volume import docker_gitea-db -

##############################################
# Pull containers
podman-compose -f docker-compose-forgejo.yml pull
Trying to pull lscr.io/linuxserver/mariadb:latest...
Trying to pull codeberg.org/forgejo/forgejo:15.0-rootless...
Getting image source signatures
Copying blob 622689a91c5c skipped: already exists  
Copying blob b154e1a656ce skipped: already exists  
Copying blob cf176656ebd6 skipped: already exists  
Copying blob 3dd72f43f028 skipped: already exists  
Copying blob 03cb7c4c8bca skipped: already exists  
Copying blob 4ad52f698c1f skipped: already exists  
Copying blob 5e0d54eacab6 skipped: already exists  
Copying blob f310d650979a skipped: already exists  
Copying blob d725f44b74ba skipped: already exists  
Copying blob 43030eae6df4 skipped: already exists  
Copying blob 4f4fb700ef54 skipped: already exists  
Copying blob 6a0ac1617861 skipped: already exists  
Copying config 57255a0094 done   | 
Writing manifest to image destination
57255a00947a43e3601ca15d6424debb1b08b15739c9638c2a2e02c74c1c70cc
Getting image source signatures
Copying blob 6198b5aa21c4 skipped: already exists  
Copying blob f6a4c3e338ed skipped: already exists  
Copying blob 635ce22f57a1 skipped: already exists  
Copying blob ddd86d26b0ed skipped: already exists  
Copying blob b48116483664 skipped: already exists  
Copying blob 5dba32312827 skipped: already exists  
Copying blob b35290be8052 skipped: already exists  
Copying blob f472500d88c7 skipped: already exists  
Copying blob f9f5923cad0b skipped: already exists  
Copying config 8d6058b2df done   | 
Writing manifest to image destination
8d6058b2df0f0908d980d61bf59d76a7bd075791951b80bec56828336b04ccd2

###################################################
## Run database only
podman-compose -f docker-compose-forgejo.yml up gitea-db
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
825ad34a2b5eb9268c59580a860ba78d01e3f241515b85ebf62960f4e0e9808f
d2db6f02ce10ae127c0615659b023725983eadd005c2640d6e84ce54be57e03a
[gitea-db]     | [migrations] started
[gitea-db]     | [migrations] no migrations found
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | 
[gitea-db]     |       ██╗     ███████╗██╗ ██████╗
[gitea-db]     |       ██║     ██╔════╝██║██╔═══██╗
[gitea-db]     |       ██║     ███████╗██║██║   ██║
[gitea-db]     |       ██║     ╚════██║██║██║   ██║
[gitea-db]     |       ███████╗███████║██║╚██████╔╝
[gitea-db]     |       ╚══════╝╚══════╝╚═╝ ╚═════╝
[gitea-db]     | 
[gitea-db]     |    Brought to you by linuxserver.io
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | 
[gitea-db]     | To support LSIO projects visit:
[gitea-db]     | https://www.linuxserver.io/donate/
[gitea-db]     | 
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | GID/UID
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | 
[gitea-db]     | User UID:    1000
[gitea-db]     | User GID:    911
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | Linuxserver.io version: 11.4.10-r0-ls213
[gitea-db]     | Build-date: 2026-04-20T04:01:28+00:00
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     |     
[gitea-db]     | [custom-init] No custom files found, skipping...
[gitea-db]     | 260421 21:58:17 mysqld_safe Logging to '/config/databases/d2db6f02ce10.err'.
[gitea-db]     | 260421 21:58:18 mysqld_safe Starting mariadbd daemon with databases from /config/databases
[gitea-db]     | Connection to localhost (::1) 3306 port [tcp/mysql] succeeded!
[gitea-db]     | 
[gitea-db]     | #####################################################################################
[gitea-db]     | #                                                                                   #
[gitea-db]     | #                             Logrotate Instructions                                #
[gitea-db]     | #                                                                                   #
[gitea-db]     | #               Add the following to /config/custom.cnf under [mysqld]:             #
[gitea-db]     | #                  log_error = /config/log/mysql/mariadb-error.log                  #
[gitea-db]     | #                                                                                   #
[gitea-db]     | #                 Login to the SQL shell inside the container using:                #
[gitea-db]     | #                           mariadb -uroot -p<PASSWORD>                             #
[gitea-db]     | #                          And run the following command:                           #
[gitea-db]     | # GRANT ALL ON *.* TO root@localhost IDENTIFIED VIA unix_socket WITH GRANT OPTION ; #
[gitea-db]     | #                                                                                   #
[gitea-db]     | #                     Restart the container to apply the changes.                   #
[gitea-db]     | #                                                                                   #
[gitea-db]     | #              You can read more about root@localhost permissions here:             #
[gitea-db]     | #             https://mariadb.com/kb/en/authentication-from-mariadb-10-4/           #
[gitea-db]     | #                                                                                   #
[gitea-db]     | #####################################################################################
[gitea-db]     | 
[gitea-db]     | #################################################################
[gitea-db]     | #                                                               #
[gitea-db]     | #           An upgrade is required on your databases.           #
[gitea-db]     | #                                                               #
[gitea-db]     | #         Stop any services that are accessing databases        #
[gitea-db]     | #          in this container, and then run the command          #
[gitea-db]     | #                                                               #
[gitea-db]     | #                   mariadb-upgrade -u root                     #
[gitea-db]     | #                                                               #
[gitea-db]     | #################################################################
[gitea-db]     | 
[gitea-db]     | [ls.io-init] done.

In 2nd terminal window (password might be in your ~/docker/.env file or somewhere)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[pavel@marten -=- ~]$ podman exec -it gitea-mariadb bash
root@d2db6f02ce10:/# vi /config/custom.cnf 
root@d2db6f02ce10:/# mariadb -uroot -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 7
Server version: 11.4.10-MariaDB-log Alpine Linux

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> GRANT ALL ON *.* TO root@localhost IDENTIFIED VIA unix_socket WITH GRANT OPTION ;
Query OK, 0 rows affected (0.002 sec)

MariaDB [(none)]> /quit
    -> \quit
Bye
root@d2db6f02ce10:/# exit
exit

In 1st terminal window Ctrl+C Ctrl+C to shutdown container. Now it should be slighly different

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[gitea-db]     | Logrotate is enabled
[gitea-db]     | 
[gitea-db]     | 
[gitea-db]     | 
[gitea-db]     | #################################################################
[gitea-db]     | #                                                               #
[gitea-db]     | #           An upgrade is required on your databases.           #
[gitea-db]     | #                                                               #
[gitea-db]     | #         Stop any services that are accessing databases        #
[gitea-db]     | #          in this container, and then run the command          #
[gitea-db]     | #                                                               #
[gitea-db]     | #                   mariadb-upgrade -u root                     #
[gitea-db]     | #                                                               #
[gitea-db]     | #################################################################
[gitea-db]     | 
[gitea-db]     | 
[gitea-db]     | 
[gitea-db]     | [ls.io-init] done.

In 2nd terminal window:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[pavel@marten -=- ~]$ podman exec -it gitea-mariadb bash
root@d2db6f02ce10:/# mariadb-upgrade -u root
Phase 1/8: Checking and upgrading mysql database
Processing databases
mysql
mysql.column_stats                                 OK
mysql.columns_priv                                 OK
mysql.db                                           OK
...
gitea.watch                                        OK
gitea.webauthn_credential                          OK
gitea.webhook                                      OK
information_schema
performance_schema
sys
sys.sys_config                                     OK
Phase 7/8: uninstalling plugins
Phase 8/8: Running 'FLUSH PRIVILEGES'
OK
root@d2db6f02ce10:/# exit
exit

Now start everything and try

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
[pavel@marten -=- ~/docker]$ podman-compose -f docker-compose-forgejo.yml up
dbf730f8bf83f59525e120fa8025c9dc9073b9762e42111065ae28da86c8114f
[gitea-db]     | [migrations] started
[gitea-db]     | [migrations] no migrations found
[gitea-db]     | usermod: no changes
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | 
[gitea-db]     |       ██╗     ███████╗██╗ ██████╗
[gitea-db]     |       ██║     ██╔════╝██║██╔═══██╗
[gitea-db]     |       ██║     ███████╗██║██║   ██║
[gitea-db]     |       ██║     ╚════██║██║██║   ██║
[gitea-db]     |       ███████╗███████║██║╚██████╔╝
[gitea-db]     |       ╚══════╝╚══════╝╚═╝ ╚═════╝
[gitea-db]     | 
[gitea-db]     |    Brought to you by linuxserver.io
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | 
[gitea-db]     | To support LSIO projects visit:
[gitea-db]     | https://www.linuxserver.io/donate/
[gitea-db]     | 
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | GID/UID
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | 
[gitea-db]     | User UID:    1000
[gitea-db]     | User GID:    911
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     | Linuxserver.io version: 11.4.10-r0-ls213
[gitea-db]     | Build-date: 2026-04-20T04:01:28+00:00
[gitea-db]     | ───────────────────────────────────────
[gitea-db]     |     
[gitea-db]     | [custom-init] No custom files found, skipping...
[gitea-server] | WARNING: detected configuration file in deprecated default path /etc/gitea/app.ini. The new default is /var/lib/gitea/custom/conf/app.ini. To remove this warning, choose one of the options:
[gitea-server] |  * Move /etc/gitea/app.ini to /var/lib/gitea/custom/conf/app.ini (or to $GITEA_APP_INI if you want to override this variable)
[gitea-server] |  * Explicitly override GITEA_APP_INI=/etc/gitea/app.ini in the container environment
[gitea-db]     | 260421 22:08:17 mysqld_safe Logging to '/config/databases/d2db6f02ce10.err'.
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:253:runWeb() [I] Starting Forgejo on PID: 2
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:112:showWebStartupMessage() [I] Forgejo version: 11.0.12+gitea-1.22.0 built with GNU Make 4.4.1, go1.25.9 : bindata, timetzdata, sqlite, sqlite_unlock_notify
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:113:showWebStartupMessage() [I] * RunMode: prod
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:114:showWebStartupMessage() [I] * AppPath: /usr/local/bin/gitea
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:115:showWebStartupMessage() [I] * WorkPath: /var/lib/gitea
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:116:showWebStartupMessage() [I] * CustomPath: /var/lib/gitea/custom
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:117:showWebStartupMessage() [I] * ConfigFile: /etc/gitea/app.ini
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:118:showWebStartupMessage() [I] Prepare to run web server
[gitea-db]     | 260421 22:08:17 mysqld_safe Starting mariadbd daemon with databases from /config/databases
[gitea-server] | 2026/04/21 22:08:17 routers/init.go:114:InitWebInstalled() [I] Git version: 2.49.1, Wire Protocol Version 2 Enabled (home: /var/lib/gitea/home)
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:157:initAttachments() [I] Initialising Attachment storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/data/attachments
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:147:initAvatars() [I] Initialising Avatar storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/data/avatars
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:173:initRepoAvatars() [I] Initialising Repository Avatar storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/data/repo-avatars
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:167:initLFS() [I] Initialising LFS storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/git/lfs
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:179:initRepoArchives() [I] Initialising Repository Archive storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/repo-archive
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:189:initPackages() [I] Initialising Packages storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/packages
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:200:initActions() [I] Initialising Actions storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/actions_log
[gitea-server] | 2026/04/21 22:08:17 ...s/storage/storage.go:204:initActions() [I] Initialising ActionsArtifacts storage with type: local
[gitea-server] | 2026/04/21 22:08:17 ...les/storage/local.go:33:NewLocalStorage() [I] Creating new Local Storage at /var/lib/gitea/actions_artifacts
[gitea-server] | 2026/04/21 22:08:17 routers/init.go:133:InitWebInstalled() [I] SQLite3 support is enabled
[gitea-server] | 2026/04/21 22:08:17 routers/common/db.go:23:InitDBEngine() [I] Beginning ORM engine initialization.
[gitea-server] | 2026/04/21 22:08:17 routers/common/db.go:30:InitDBEngine() [I] ORM engine initialization attempt #1/10...
[gitea-server] | 2026/04/21 22:08:17 cmd/web.go:205:serveInstalled() [I] PING DATABASE mysql
[gitea-server] | 2026/04/21 22:08:17 routers/common/db.go:36:InitDBEngine() [E] ORM engine initialization attempt #1/10 failed. Error: dial tcp 10.89.0.34:3306: connect: connection refused
[gitea-server] | 2026/04/21 22:08:17 routers/common/db.go:37:InitDBEngine() [I] Backing off for 3 seconds
[gitea-db]     | Connection to localhost (::1) 3306 port [tcp/mysql] succeeded!
[gitea-db]     | Logrotate is enabled
[gitea-db]     | [ls.io-init] done.
[gitea-server] | 2026/04/21 22:08:20 routers/common/db.go:30:InitDBEngine() [I] ORM engine initialization attempt #2/10...
[gitea-server] | 2026/04/21 22:08:20 cmd/web.go:205:serveInstalled() [I] PING DATABASE mysql
[gitea-server] | 2026/04/21 22:08:21 ...dels/db/collation.go:153:preprocessDatabaseCollation() [W] Current database is using a case-insensitive collation "utf8mb4_general_ci", although Forgejo could work with it, there might be some rare cases which don't work as expected.
[gitea-server] | 2026/04/21 22:08:21 cmd/web.go:205:serveInstalled() [W] Table project column board_type db type is INT(10) UNSIGNED, struct type is INT UNSIGNED
[gitea-server] | 2026/04/21 22:08:21 cmd/web.go:205:serveInstalled() [W] Table project column card_type db type is INT(10) UNSIGNED, struct type is INT UNSIGNED
[gitea-server] | 2026/04/21 22:08:21 cmd/web.go:205:serveInstalled() [W] Table project column type db type is INT(10) UNSIGNED, struct type is INT UNSIGNED
[gitea-server] | 2026/04/21 22:08:21 routers/init.go:139:InitWebInstalled() [I] ORM engine initialization successful!
[gitea-server] | 2026/04/21 22:08:21 ...er/issues/indexer.go:78:func1() [I] PID 2: Initializing Issue Indexer: bleve
[gitea-server] | 2026/04/21 22:08:21 ...xer/stats/indexer.go:41:populateRepoIndexer() [I] Populating the repo stats indexer with existing repositories
[gitea-server] | 2026/04/21 22:08:21 ...xer/stats/indexer.go:87:populateRepoIndexer() [I] Done (re)populating the repo stats indexer with existing repositories
[gitea-server] | 2026/04/21 22:08:21 ...er/issues/indexer.go:155:func2() [I] Issue Indexer Initialization took 2.405544ms
[gitea-server] | 2026/04/21 22:08:21 modules/ssh/ssh.go:332:Listen() [I] Adding SSH host key: /var/lib/gitea/ssh/gitea.rsa
[gitea-server] | 2026/04/21 22:08:21 modules/ssh/init.go:26:Init() [I] SSH server started on :2222. Cipher list ([[email protected] aes128-ctr aes192-ctr aes256-ctr [email protected] [email protected]]), key exchange algorithms ([curve25519-sha256 ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 diffie-hellman-group14-sha256 diffie-hellman-group14-sha1]), MACs ([[email protected] hmac-sha2-256 hmac-sha1])
[gitea-server] | 2026/04/21 22:08:21 ...s/graceful/server.go:50:NewServer() [I] Starting new SSH server: tcp::2222 on PID: 2
[gitea-server] | 2026/04/21 22:08:21 ...er/cleanup_sha256.go:27:CleanupSHA256() [I] Start to cleanup dangling images with a sha256:* version
[gitea-server] | 2026/04/21 22:08:21 ...er/cleanup_sha256.go:106:cleanupSHA256() [I] Nothing to cleanup
[gitea-server] | 2026/04/21 22:08:21 ...er/cleanup_sha256.go:29:CleanupSHA256() [I] Finished to cleanup dangling images with a sha256:* version
[gitea-server] | 2026/04/21 22:08:21 cmd/web.go:315:listen() [I] Listen: http://0.0.0.0:3000
[gitea-server] | 2026/04/21 22:08:21 cmd/web.go:319:listen() [I] AppURL(ROOT_URL): https://git.pavelp.cz/
[gitea-server] | 2026/04/21 22:08:21 cmd/web.go:322:listen() [I] LFS server enabled
[gitea-server] | 2026/04/21 22:08:21 ...s/graceful/server.go:50:NewServer() [I] Starting new Web server: tcp:0.0.0.0:3000 on PID: 2
[gitea-server] | 2026/04/21 22:08:32 ...eb/routing/logger.go:102:func1() [I] router: completed GET / for 89.102.37.225:0, 200 OK in 6.2ms @ web/home.go:32(web.Home)
[gitea-server] | 2026/04/21 22:08:37 ...eb/routing/logger.go:102:func1() [I] router: completed GET /user/login?redirect_to=%2f for 89.102.37.225:0, 200 OK in 7.7ms @ auth/auth.go:145(auth.SignIn)
[gitea-server] | 2026/04/21 22:08:39 ...eb/routing/logger.go:102:func1() [I] router: completed POST /user/login for 89.102.37.225:0, 303 See Other in 71.0ms @ auth/auth.go:179(auth.SignInPost)
[gitea-server] | 2026/04/21 22:08:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET / for 89.102.37.225:0, 200 OK in 59.1ms @ web/home.go:32(web.Home)
[gitea-server] | 2026/04/21 22:08:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET /avatar/b20f8607faa9ee279794ba4c56ba2dd9?size=56 for 89.102.37.225:0, 303 See Other in 29.8ms @ user/avatar.go:48(user.AvatarByEmailHash)
[gitea-server] | 2026/04/21 22:08:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET /avatar/b20f8607faa9ee279794ba4c56ba2dd9?size=48 for 89.102.37.225:0, 303 See Other in 29.6ms @ user/avatar.go:48(user.AvatarByEmailHash)
[gitea-server] | 2026/04/21 22:08:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET /repo/search?count_only=1&uid=1&team_id=undefined&q=&page=1&mode= for 89.102.37.225:0, 200 OK in 6.8ms @ repo/repo.go:593(repo.SearchRepo)
[gitea-server] | 2026/04/21 22:08:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET /avatar/cf6b7f76993d737ca8f70880b830e13c?size=56 for 89.102.37.225:0, 303 See Other in 57.1ms @ user/avatar.go:48(user.AvatarByEmailHash)
[gitea-server] | 2026/04/21 22:08:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET /repo/search?sort=updated&order=desc&uid=1&team_id=undefined&q=&page=1&limit=15&mode=&archived=false for 89.102.37.225:0, 200 OK in 27.3ms @ repo/repo.go:593(repo.SearchRepo)
[gitea-server] | 2026/04/21 22:08:43 ...eb/routing/logger.go:68:func1() [I] router: polling   GET /user/events for 89.102.37.225:0, elapsed 3525.4ms @ events/events.go:18(events.Events)
[gitea-server] | 2026/04/21 22:09:40 ...eb/routing/logger.go:102:func1() [I] router: completed GET /user/events for 89.102.37.225:0, 200 OK in 60020.5ms @ events/events.go:18(events.Events)

Issue #2: Config file location

WAIT! THIS IS INTERESTING

1
2
3
[gitea-server] | WARNING: detected configuration file in deprecated default path /etc/gitea/app.ini. The new default is /var/lib/gitea/custom/conf/app.ini. To remove this warning, choose one of the options:
[gitea-server] |  * Move /etc/gitea/app.ini to /var/lib/gitea/custom/conf/app.ini (or to $GITEA_APP_INI if you want to override this variable)
[gitea-server] |  * Explicitly override GITEA_APP_INI=/etc/gitea/app.ini in the container environment

Nonetheless Forgejo works. Well. Stop it, backup updated database, just in case we will need it again:

1
podman volume export docker_gitea-db | zstd -11 > ~/backup/gitea-db-2026-04-21-newdb.tar.zst

Now I see. Current config uses volume - gitea-config:/etc/gitea which contains only app.ini file

Now black magic podman unshare command to access data inside volumes. Note output of ID commands:

1
2
3
4
5
6
7
8
9
10
id
# uid=1000(pavel) gid=1000(pavel) groups=1000(pavel),10(wheel),18(dialout) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
podman unshare bash
id
# uid=0(root) gid=0(root) groups=0(root),65534(nobody) context=unconfined_u:unconfined_r:container_runtime_t:s0-s0:c0.c1023
cd /home/pavel/.local/share/containers/storage/volumes
diff -y docker_gitea-config/_data/app.ini docker_gitea-data/_data/custom/conf/app.ini
cp docker_gitea-config/_data/app.ini docker_gitea-data/_data/custom/conf/app.ini
exit

This copies old file to new one (which might have been created by new version of Forgejo) Now we can remove mounting gitea-config volume and switch version. Honestly maybe we should restore data volume and copy this file again. Let’s do it. So again, restore last Forgejo 11:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Remove containers and volumes
podman container rm b34071ff5d2a 45a23d11b349
podman volume rm docker_gitea-db docker_gitea-data
podman volume create docker_gitea-db
podman volume create docker_gitea-data
# Restore backup (updated Forgejo11 database and data prior to the very first attempt to run Forgejo 15)
zstd -d < ~/backup/gitea-db-2026-04-21-newdb.tar.zst | podman volume import docker_gitea-db -
zstd -d < ~/backup/gitea-data-2026-04-21.tar.zst     | podman volume import docker_gitea-data -
# Copy config to the new location
podman unshare bash
# Here we do not have conf directory, it was obviously created by Forgejo 15
cd /home/pavel/.local/share/containers/storage/volumes
mkdir -p docker_gitea-data/_data/custom/conf/
cp docker_gitea-config/_data/app.ini docker_gitea-data/_data/custom/conf/app.ini
# Leave shell with container root user
exit
# Download containers
podman-compose -f docker-compose-forgejo.yml pull
# Run in foreground (add -d for background)
podman-compose -f docker-compose-forgejo.yml up

Issue 3: File permissions

1
[gitea-server] | 2026/04/21 22:56:08 ...s/setting/setting.go:94:InitCfgProvider() [F] Unable to init config provider from "/var/lib/gitea/custom/conf/app.ini": failed to load config file "/var/lib/gitea/custom/conf/app.ini": open /var/lib/gitea/custom/conf/app.ini: permission denied
1
2
[gitea-server] | 2026/04/21 22:58:47 ...g/config_provider.go:349:deprecatedSettingWarning() [E] Deprecated config option `[log]` `logger.router.MODE` present. Use `[log]` `LOGGER_ROUTER_MODE` instead.
[gitea-server] | 2026/04/21 22:58:47 ...odules/setting/f3.go:39:loadF3From() [F] Failed to create F3 path /var/lib/gitea/f3: mkdir /var/lib/gitea/f3: permission denied

Now I needed to fix permissions: podman unshare bash, change directory chown pavel:pavel app.ini and cd /home/pavel/.local/share/containers/storage/volumes/docker_gitea-data/_data && chown pavel.pavel . to change /var/lib/gitea.

Next start hopefully worked.

This post is licensed under CC BY 4.0 by the author.