Description
Bug Description
When SSH host keys in the /data/ssh volume are owned by root instead of
the gitea user, the container's openssh s6 service enters a tight infinite
restart loop causing sustained 600–700% CPU usage with ~950 log lines/minute.
Environment
- Gitea version: 1.25.4 (
gitea/gitea:1.25.4)
- Deployment: Docker with bind-mount volume
- Config:
GITEA__server__START_SSH_SERVER=true
- Host OS: Linux
Steps to Reproduce
- Deploy gitea container with
START_SSH_SERVER=true and a bind-mounted /data volume
- Cause SSH host keys to be owned by
root:root on the host
(e.g. keys were generated by a previous privileged operation, or manual intervention)
- Start the container
Actual Behavior
The openssh service's setup script (/etc/s6/openssh/setup) runs:
chown root:root /data/ssh/* # fails: Operation not permitted
chmod 0700 /data/ssh # fails: Operation not permitted
chmod 0600 /data/ssh/* # fails: Operation not permitted
Because chown/chmod fail silently (non-zero exit is ignored by source),
sshd then starts but cannot load the host keys and exits immediately:
Unable to load host key: /data/ssh/ssh_host_ed25519_key
Unable to load host key: /data/ssh/ssh_host_rsa_key
Unable to load host key: /data/ssh/ssh_host_ecdsa_key
sshd: no hostkeys available -- exiting.
The finish script exits with 0, so s6 restarts the service with no delay,
creating an infinite tight loop.
Resource impact measured:
- Container CPU: 675% sustained (on 8-core host)
- Log output: ~950 lines/minute
- System load average: 8.3 (normally < 1)
Expected Behavior
When chown/chmod on SSH keys fail, the container should either:
- Exit with a clear error and not restart (or use exponential backoff), or
- Log a fatal error and gracefully disable the SSH service
Root Cause
In /etc/s6/openssh/setup, failures of chown/chmod are not checked.
In /etc/s6/openssh/run, source ./setup discards the setup exit status.
In /etc/s6/openssh/finish, exit 0 unconditionally allows immediate restart.
/etc/s6/openssh/run (current)
[[ -f ./setup ]] && source ./setup # setup failures ignored
exec su-exec root /usr/sbin/sshd -D -e 2>&1
/etc/s6/openssh/finish (current)
exit 0 # always restart
Suggested Fix
Option A — fail the setup script explicitly:
/etc/s6/openssh/setup
chown root:root /data/ssh/* || { echo "FATAL: cannot chown /data/ssh/"; exit 1; }
chmod 0700 /data/ssh || { echo "FATAL: cannot chmod /data/ssh"; exit 1; }
chmod 0600 /data/ssh/ || { echo "FATAL: cannot chmod /data/ssh/*"; exit 1; }
And in /etc/s6/openssh/run, propagate setup failure:
[[ -f ./setup ]] && { source ./setup || exit 1; }
Option B — in the finish script, use s6's mechanism to prevent restart on
immediate exit (exit code 125 tells s6 not to restart):
/etc/s6/openssh/finish
$1 = exit code of the run script, $2 = signal
if [ "$1" -ne 0 ]; then
echo "openssh exited with code $1 — not restarting"
exit 125
fi
exit 0
Additional Context
The data volume files that triggered this issue:
/data/ssh/ssh_host_ecdsa_key root:root 600
/data/ssh/ssh_host_ed25519_key root:root 600
/data/ssh/ssh_host_rsa_key root:root 600
Container runs with USER_UID=3001 / USER_GID=3001, making chown root:root
impossible for the non-privileged process inside the container.
Workaround (host-side fix):
chown 3001:3001 /path/to/gitea/data/ssh/ssh_host_*
docker restart gitea
Gitea Version
1.25.4
Can you reproduce the bug on the Gitea demo site?
No
Log Gist
No response
Screenshots
No response
Git Version
No response
Operating System
debian 12
How are you running Gitea?
Installation Source
- Used the official Docker image:
gitea/gitea:1.25.4
- Image pulled from Docker Hub (not self-built from source)
How Gitea is Running
- Running inside a Docker container via Docker Compose
- Managed through Portainer
- Relevant compose config:
image: gitea/gitea:1.25.4
environment:
USER_UID: "3001"
USER_GID: "3001"
GITEA__server__START_SSH_SERVER: "true"
volumes:
- /mnt/debian/gitea:/data
ports:
- "2222:22"
- "3000:3000"
- Host OS: Linux (Debian-based)
- Docker version: 20.10+
Database
None
Description
Bug Description
When SSH host keys in the
/data/sshvolume are owned byrootinstead ofthe gitea user, the container's
opensshs6 service enters a tight infiniterestart loop causing sustained 600–700% CPU usage with ~950 log lines/minute.
Environment
gitea/gitea:1.25.4)GITEA__server__START_SSH_SERVER=trueSteps to Reproduce
START_SSH_SERVER=trueand a bind-mounted/datavolumeroot:rooton the host(e.g. keys were generated by a previous privileged operation, or manual intervention)
Actual Behavior
The
opensshservice'ssetupscript (/etc/s6/openssh/setup) runs:chown root:root /data/ssh/* # fails: Operation not permitted
chmod 0700 /data/ssh # fails: Operation not permitted
chmod 0600 /data/ssh/* # fails: Operation not permitted
Because chown/chmod fail silently (non-zero exit is ignored by source),
sshd then starts but cannot load the host keys and exits immediately:
Unable to load host key: /data/ssh/ssh_host_ed25519_key
Unable to load host key: /data/ssh/ssh_host_rsa_key
Unable to load host key: /data/ssh/ssh_host_ecdsa_key
sshd: no hostkeys available -- exiting.
The finish script exits with 0, so s6 restarts the service with no delay,
creating an infinite tight loop.
Resource impact measured:
Expected Behavior
When chown/chmod on SSH keys fail, the container should either:
Root Cause
In /etc/s6/openssh/setup, failures of chown/chmod are not checked.
In /etc/s6/openssh/run, source ./setup discards the setup exit status.
In /etc/s6/openssh/finish, exit 0 unconditionally allows immediate restart.
/etc/s6/openssh/run (current)
[[ -f ./setup ]] && source ./setup # setup failures ignored
exec su-exec root /usr/sbin/sshd -D -e 2>&1
/etc/s6/openssh/finish (current)
exit 0 # always restart
Suggested Fix
Option A — fail the setup script explicitly:
/etc/s6/openssh/setup
chown root:root /data/ssh/* || { echo "FATAL: cannot chown /data/ssh/"; exit 1; }
chmod 0700 /data/ssh || { echo "FATAL: cannot chmod /data/ssh"; exit 1; }
chmod 0600 /data/ssh/ || { echo "FATAL: cannot chmod /data/ssh/*"; exit 1; }
And in /etc/s6/openssh/run, propagate setup failure:
[[ -f ./setup ]] && { source ./setup || exit 1; }
Option B — in the finish script, use s6's mechanism to prevent restart on
immediate exit (exit code 125 tells s6 not to restart):
/etc/s6/openssh/finish
$1 = exit code of the run script, $2 = signal
if [ "$1" -ne 0 ]; then
echo "openssh exited with code $1 — not restarting"
exit 125
fi
exit 0
Additional Context
The data volume files that triggered this issue:
/data/ssh/ssh_host_ecdsa_key root:root 600
/data/ssh/ssh_host_ed25519_key root:root 600
/data/ssh/ssh_host_rsa_key root:root 600
Container runs with USER_UID=3001 / USER_GID=3001, making chown root:root
impossible for the non-privileged process inside the container.
Workaround (host-side fix):
chown 3001:3001 /path/to/gitea/data/ssh/ssh_host_*
docker restart gitea
Gitea Version
1.25.4
Can you reproduce the bug on the Gitea demo site?
No
Log Gist
No response
Screenshots
No response
Git Version
No response
Operating System
debian 12
How are you running Gitea?
Installation Source
gitea/gitea:1.25.4How Gitea is Running
image: gitea/gitea:1.25.4
environment:
USER_UID: "3001"
USER_GID: "3001"
GITEA__server__START_SSH_SERVER: "true"
volumes:
ports:
Database
None