I wanted to access an Ollama server running on Fedora from another Linux machine without exposing Ollama directly to the network.
Ollama was listening only on:
127.0.0.1:11434
The obvious solution was an SSH local tunnel:
ssh -N -L 11434:127.0.0.1:11434 user@SERVER_IP
This should make the remote Ollama API available on the client at:
http://127.0.0.1:11434
However, SSH returned:
channel 2: open failed: connect failed: open failed
1. Verify the service
First, I confirmed that Ollama itself worked on the Fedora server:
curl http://127.0.0.1:11434/api/version
It returned:
{"version":"0.34.0"}
So Ollama was not the problem.
I also checked SSH forwarding:
sudo sshd -T | grep -E 'allowtcpforwarding|disableforwarding|permitopen'
The relevant settings allowed forwarding:
allowtcpforwarding yes
disableforwarding no
permitopen any
2. Check SELinux
Fedora runs SELinux in enforcing mode, so I checked recent denials:
sudo ausearch -m AVC -ts recent
The important part was:
avc: denied { name_connect }
comm="sshd-session"
dest=11434
scontext=...sshd_session_t...
tcontext=...unreserved_port_t...
So SSH forwarding was allowed by sshd, but SELinux was preventing the SSH session from connecting to port 11434.
3. Label the Ollama port
Because Ollama provides an HTTP API, I classified TCP port 11434 as http_port_t:
sudo dnf install policycoreutils-python-utils
sudo semanage port -a \
-t http_port_t \
-p tcp 11434
Verify it:
sudo semanage port -l | grep 11434
This changed the SELinux target from unreserved_port_t to http_port_t, but SSH was still denied.
4. Add a narrow SELinux rule
The missing permission was:
sshd_session_t → http_port_t → name_connect
Instead of disabling SELinux, I created a small local policy:
cat > ~/ssh-forward.te <<'EOF'
module ssh-forward 1.0;
require {
type http_port_t;
type sshd_session_t;
class tcp_socket name_connect;
}
allow sshd_session_t http_port_t:tcp_socket name_connect;
EOF
Compile and install it:
sudo dnf install checkpolicy policycoreutils
cd ~
checkmodule -M -m \
-o ssh-forward.mod ssh-forward.te
semodule_package \
-o ssh-forward.pp \
-m ssh-forward.mod
sudo semodule -i ssh-forward.pp
Verify:
sudo semodule -l | grep ssh-forward
Optionally, install sesearch:
sudo dnf install setools-console
and confirm the permission:
sudo sesearch -A \
-s sshd_session_t \
-t http_port_t \
-c tcp_socket \
-p name_connect
The result should include:
allow sshd_session_t http_port_t:tcp_socket name_connect;
5. Test the tunnel
Back on the client:
ssh -N -L 11434:127.0.0.1:11434 user@SERVER_IP
Then, from another client terminal:
curl http://127.0.0.1:11434/api/version
It now returned:
{"version":"0.34.0"}
The tunnel was working.
Why use this approach?
I could have configured Ollama to listen on 0.0.0.0:11434 and opened the firewall port, but that would expose its API to the local network.
Instead, the final setup is:
Client
127.0.0.1:11434
│
│ SSH tunnel
▼
Fedora Server
│
▼
127.0.0.1:11434
│
▼
Ollama
Ollama remains localhost-only, while authorized SSH users can access it securely.
Most importantly, SELinux remains in enforcing mode. There is no need to use setenforce 0 just to make SSH forwarding work.
If an SSH tunnel on Fedora gives:
channel N: open failed: connect failed: open failed
despite the destination service working locally, checking the SELinux AVC log with:
sudo ausearch -m AVC -ts recent
may reveal the actual cause.
Yorumlar