summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-02-18 15:12:32 +0800
committerYour Name <you@example.com>2026-02-18 15:12:32 +0800
commitc3a377a265d2ca92b8823be281fa0e487d30692b (patch)
tree1d5b4213c65635ffdd82921b633eaaf5bebd2e60
parentb0572c958427ae6ad75109752e9741aab31ad65a (diff)
switch to rocky linux 10, add --init for zombie reaping, fix NAT setup
- base image alpine -> rockylinux:10 (cgit/fcgiwrap from EPEL) - drop spawn-fcgi, use fcgiwrap -s directly - add --init to reap zombie sshd-auth processes (PID exhaustion fix) - replace ip addr/route networking with nft DNAT/SNAT/FORWARD rules - add FORWARD accept rule that was missing for inbound DNAT traffic
-rw-r--r--Caddyfile6
-rw-r--r--Dockerfile10
-rw-r--r--entrypoint.sh5
-rw-r--r--sshd_config2
-rwxr-xr-xstart_container.sh21
5 files changed, 29 insertions, 15 deletions
diff --git a/Caddyfile b/Caddyfile
index b783e7b..7458b93 100644
--- a/Caddyfile
+++ b/Caddyfile
@@ -1,18 +1,18 @@
1{$DOMAIN} { 1{$DOMAIN} {
2 handle {$CGIT_CSS} { 2 handle {$CGIT_CSS} {
3 root * /usr/share/webapps/cgit 3 root * /usr/share/cgit
4 file_server 4 file_server
5 } 5 }
6 6
7 handle {$CGIT_LOGO} { 7 handle {$CGIT_LOGO} {
8 root * /usr/share/webapps/cgit 8 root * /usr/share/cgit
9 file_server 9 file_server
10 } 10 }
11 11
12 handle { 12 handle {
13 reverse_proxy unix/{$FCGI_SOCK} { 13 reverse_proxy unix/{$FCGI_SOCK} {
14 transport fastcgi { 14 transport fastcgi {
15 env SCRIPT_FILENAME /usr/share/webapps/cgit/cgit.cgi 15 env SCRIPT_FILENAME /var/www/cgi-bin/cgit
16 env QUERY_STRING {query} 16 env QUERY_STRING {query}
17 env HTTP_HOST {host} 17 env HTTP_HOST {host}
18 env PATH_INFO {path} 18 env PATH_INFO {path}
diff --git a/Dockerfile b/Dockerfile
index 86352b4..65ead86 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,16 @@
1FROM alpine:latest 1FROM rockylinux:10
2 2
3RUN apk add --no-cache \ 3RUN dnf install -y epel-release && \
4 dnf copr enable -y @caddy/caddy && \
5 dnf install -y \
4 caddy \ 6 caddy \
5 cgit \ 7 cgit \
6 git \ 8 git \
7 fcgiwrap \ 9 fcgiwrap \
8 spawn-fcgi \
9 gettext \ 10 gettext \
10 openssl \ 11 openssl \
11 openssh-server 12 openssh-server \
13 && dnf clean all
12 14
13COPY cgitrc.template /etc/cgitrc.template 15COPY cgitrc.template /etc/cgitrc.template
14COPY Caddyfile /etc/caddy/Caddyfile 16COPY Caddyfile /etc/caddy/Caddyfile
diff --git a/entrypoint.sh b/entrypoint.sh
index 3e2dcc0..ba24e29 100644
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,4 +1,4 @@
1#!/bin/sh 1#!/bin/bash
2set -e 2set -e
3 3
4# Check cert matches domain, else clear and renew 4# Check cert matches domain, else clear and renew
@@ -21,7 +21,8 @@ chmod 700 /git/.ssh
21chmod 600 /git/.ssh/authorized_keys 21chmod 600 /git/.ssh/authorized_keys
22/usr/sbin/sshd 22/usr/sbin/sshd
23 23
24spawn-fcgi -s ${FCGI_SOCK} /usr/bin/fcgiwrap 24fcgiwrap -s unix:${FCGI_SOCK} &
25sleep 0.5
25chmod 666 ${FCGI_SOCK} 26chmod 666 ${FCGI_SOCK}
26 27
27exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile 28exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
diff --git a/sshd_config b/sshd_config
index 5d31e36..0270433 100644
--- a/sshd_config
+++ b/sshd_config
@@ -7,4 +7,4 @@ AuthorizedKeysFile /git/.ssh/authorized_keys
7MaxStartups 3:50:10 7MaxStartups 3:50:10
8# Kill unauthenticated connections after 15 seconds 8# Kill unauthenticated connections after 15 seconds
9LoginGraceTime 15 9LoginGraceTime 15
10Subsystem sftp /usr/lib/ssh/sftp-server 10Subsystem sftp /usr/libexec/openssh/sftp-server
diff --git a/start_container.sh b/start_container.sh
index 2299390..f93f5df 100755
--- a/start_container.sh
+++ b/start_container.sh
@@ -29,6 +29,7 @@ podman build -t cgit "$(dirname "$0")"
29 29
30# Run container 30# Run container
31podman run -d \ 31podman run -d \
32 --init \
32 --name ${CONTAINER_NAME} \ 33 --name ${CONTAINER_NAME} \
33 --network ${NETWORK} \ 34 --network ${NETWORK} \
34 --ip ${PRIVATE_IP} \ 35 --ip ${PRIVATE_IP} \
@@ -39,11 +40,21 @@ podman run -d \
39 -v /git:/git \ 40 -v /git:/git \
40 localhost/cgit 41 localhost/cgit
41 42
42# Setup public IP 43# Setup public IP via DNAT/SNAT
43sleep 2 44sleep 2
44# Get the container's network interface name (e.g. eth0) 45OIFACE=$(ip route show default | awk '{print $5; exit}')
45IFACE=$(podman exec ${CONTAINER_NAME} sh -c "ip -o link | grep -v lo | head -1 | cut -d: -f2 | tr -d ' ' | cut -d@ -f1") 46BRIDGE=$(podman network inspect ${NETWORK} 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin)[0]['network_interface'])")
46podman exec ${CONTAINER_NAME} ip addr add ${PUBLIC_IP}/32 dev ${IFACE} 47
47ip route add ${PUBLIC_IP}/32 via ${PRIVATE_IP} 48# Clean up any stale rules for this IP
49nft -a list chain ip nat PREROUTING 2>/dev/null | grep "daddr ${PUBLIC_IP} " | grep -oP 'handle \K\d+' | while read h; do nft delete rule ip nat PREROUTING handle "$h"; done
50nft -a list chain ip nat POSTROUTING 2>/dev/null | grep "snat to ${PUBLIC_IP}" | grep -oP 'handle \K\d+' | while read h; do nft delete rule ip nat POSTROUTING handle "$h"; done
51nft -a list chain inet netavark FORWARD 2>/dev/null | grep "daddr ${PRIVATE_IP} " | grep -oP 'handle \K\d+' | while read h; do nft delete rule inet netavark FORWARD handle "$h"; done
52nft -a list chain ip nat POSTROUTING 2>/dev/null | grep "daddr ${PRIVATE_IP}.*masquerade" | grep -oP 'handle \K\d+' | while read h; do nft delete rule ip nat POSTROUTING handle "$h"; done
53ip route del ${PUBLIC_IP} 2>/dev/null || true
54
55nft add rule ip nat PREROUTING ip daddr ${PUBLIC_IP} dnat to ${PRIVATE_IP}
56nft add rule ip nat POSTROUTING ip saddr ${PRIVATE_IP} oifname ${OIFACE} snat to ${PUBLIC_IP}
57nft insert rule inet netavark FORWARD ip daddr ${PRIVATE_IP} oifname ${BRIDGE} accept
58nft add rule ip nat POSTROUTING ip saddr ${PRIVATE_SUBNET} ip daddr ${PRIVATE_IP} oifname ${BRIDGE} masquerade
48 59
49echo "Running at https://${DOMAIN}/" 60echo "Running at https://${DOMAIN}/"