mirror of
https://gitea.com/gitea/docs.git
synced 2026-11-05 01:25:46 +00:00
<!-- cloudflare-preview --> Preview: https://pr-564.docs-gitea-com.pages.dev Reviewed-on: https://gitea.com/gitea/docs/pulls/564 Reviewed-by: bircni <[email protected]> Co-authored-by: Lunny Xiao <[email protected]>
110 lines
3.9 KiB
Markdown
110 lines
3.9 KiB
Markdown
---
|
|
date: "2026-08-13T00:00:00+00:00"
|
|
slug: "selinux"
|
|
sidebar_position: 45
|
|
---
|
|
|
|
# Running Gitea with SELinux
|
|
|
|
Distributions such as Fedora, RHEL, CentOS Stream, Rocky Linux and AlmaLinux
|
|
ship SELinux in enforcing mode. Packages from a distribution repository come
|
|
with a policy that fits them, but an installation
|
|
[from binary](from-binary.md) or [from source](from-source.md) puts the binary
|
|
and the data in paths the policy knows nothing about, so the labels have to be
|
|
set by hand. The same applies to any other distribution where SELinux is
|
|
enabled.
|
|
|
|
Do not turn SELinux off to work around the problems below. `setenforce 0` is
|
|
useful to confirm that a failure really comes from SELinux, but switch it back
|
|
on with `setenforce 1` afterwards.
|
|
|
|
## Binding to a port below 1024
|
|
|
|
Gitea should not run as root, and an unprivileged process may not bind to a
|
|
port below 1024. Granting the capability to the binary with
|
|
`setcap 'cap_net_bind_service=+ep' /usr/local/bin/gitea` is often suggested,
|
|
but it is the least robust option:
|
|
|
|
- file capabilities are stored in an extended attribute of the binary, so they
|
|
are lost every time the binary is replaced, which happens on every upgrade.
|
|
- the SELinux policy has to allow the capability for the label of the binary,
|
|
and a binary in a path such as `/opt` usually does not carry a label that
|
|
allows it.
|
|
|
|
Let systemd grant the capability to the process instead. It works with SELinux
|
|
in enforcing mode and survives upgrades, the sample unit file has the two lines
|
|
commented out:
|
|
|
|
```ini title="/etc/systemd/system/gitea.service"
|
|
[Service]
|
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
|
```
|
|
|
|
Reload and restart the service afterwards:
|
|
|
|
```sh
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl restart gitea
|
|
```
|
|
|
|
If the capability still does not reach the process, add `PrivateUsers=false` to
|
|
the unit: the sandboxing runs the service in a user namespace where the
|
|
capability does not apply to the host.
|
|
|
|
Two alternatives avoid the privileged port altogether, and are what most
|
|
installations end up doing:
|
|
|
|
- put a [reverse proxy](../administration/reverse-proxies.md) in front of Gitea
|
|
and let it own ports `80` and `443`.
|
|
- redirect the port in the firewall, for example with
|
|
`firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=3000`.
|
|
|
|
## Labelling the binary and the data directory
|
|
|
|
If Gitea starts but cannot read its own files, or fails in ways that are not
|
|
explained by the file permissions, the labels are usually wrong. The tools come
|
|
from the `policycoreutils-python-utils` package.
|
|
|
|
Label the binary as an executable and the data directory as application state:
|
|
|
|
```sh
|
|
sudo semanage fcontext -a -t bin_t '/usr/local/bin/gitea'
|
|
sudo restorecon -v /usr/local/bin/gitea
|
|
|
|
sudo semanage fcontext -a -t var_lib_t '/var/lib/gitea(/.*)?'
|
|
sudo restorecon -Rv /var/lib/gitea
|
|
```
|
|
|
|
`semanage fcontext` records the rule, `restorecon` applies it to the files that
|
|
are already there. Use the two together rather than `chcon`, whose labels are
|
|
reverted by the next relabel of the file system.
|
|
|
|
Adjust the paths if the installation does not follow
|
|
[installation from binary](from-binary.md); the configuration in `/etc/gitea`
|
|
is read with the label distributions give to `/etc`, so it normally needs
|
|
nothing.
|
|
|
|
## Finding out what was denied
|
|
|
|
SELinux denials are written to the audit log, not to the Gitea log, so a
|
|
failure often looks like a permission problem without any further explanation:
|
|
|
|
```sh
|
|
sudo ausearch -m AVC -c gitea --start recent
|
|
```
|
|
|
|
If a denial shows up that the rules above do not cover, turn it into a local
|
|
policy module. Read what it allows before installing it, `audit2allow` writes
|
|
down whatever was denied, including the things that were denied for a good
|
|
reason:
|
|
|
|
```sh
|
|
sudo ausearch -c gitea --raw | audit2allow -M gitea-local
|
|
cat gitea-local.te
|
|
sudo semodule -i gitea-local.pp
|
|
```
|
|
|
|
If the denials point at a path Gitea should not be using at all, fix the path
|
|
instead of allowing the access.
|