diff --git a/.gitea/workflows/build-publish.yml b/.gitea/workflows/build-publish.yml index 3b705e2..b76c8fa 100644 --- a/.gitea/workflows/build-publish.yml +++ b/.gitea/workflows/build-publish.yml @@ -15,11 +15,13 @@ jobs: include: - target: trixie image: debian:13 + distro_dir: Trixie nexus_repo_secret: NEXUS_REPO_TRIXIE nexus_user_secret: NEXUS_USER_TRIXIE nexus_pass_secret: NEXUS_PASS_TRIXIE - target: raccoon image: ubuntu:26.04 + distro_dir: Raccoon nexus_repo_secret: NEXUS_REPO_RACCOON nexus_user_secret: NEXUS_USER_RACCOON nexus_pass_secret: NEXUS_PASS_RACCOON @@ -41,82 +43,90 @@ jobs: id: pkg env: TARGET: ${{ matrix.target }} + DISTRO_DIR: ${{ matrix.distro_dir }} run: | set -euo pipefail + REPO_ROOT="$PWD" # captured before any cd in the build script touch /.dockerenv bash build/${TARGET}.sh new bash build/${TARGET}.sh build bash build/${TARGET}.sh postfix - PKG_NAME="twiy" NGINX_VER="$(nginx -v 2>&1 | awk -F/ '{print $2}')" VERSION="${NGINX_VER}-${GITHUB_RUN_NUMBER:-1}~${TARGET}" ARCH="amd64" - PKG_DIR="/opt/${PKG_NAME}_${VERSION}_${ARCH}" - DEB_DIR="${PKG_DIR}/DEBIAN" - mkdir -p "${PKG_DIR}/usr/sbin" "${PKG_DIR}/nginx" \ - "${PKG_DIR}/etc/systemd/system" "${PKG_DIR}/var/log/nginx" \ - "${PKG_DIR}/usr/lib" \ - "${PKG_DIR}/hostdata/default/public_html" \ - "${PKG_DIR}/usr/nginx_lua" + assemble_deb() { + local pkg_name="$1" unit_src="$2" conflicts="$3" + local pkg_dir="/opt/${pkg_name}_${VERSION}_${ARCH}" + local deb_dir="${pkg_dir}/DEBIAN" - cp /usr/sbin/nginx "${PKG_DIR}/usr/sbin/" - cp -R /nginx/* "${PKG_DIR}/nginx/" || true - cp /etc/systemd/system/nginx.service "${PKG_DIR}/etc/systemd/system/" - cp -R /hostdata/default "${PKG_DIR}/hostdata/" || true - cp -R /usr/nginx_lua "${PKG_DIR}/usr/" || true + mkdir -p "${pkg_dir}/usr/sbin" "${pkg_dir}/nginx" \ + "${pkg_dir}/etc/systemd/system" "${pkg_dir}/var/log/nginx" \ + "${pkg_dir}/usr/lib" \ + "${pkg_dir}/hostdata/default/public_html" \ + "${pkg_dir}/usr/nginx_lua" - for d in /usr/local/aws-lc /usr/local/LuaJIT /usr/local/modsecurity /usr/local/zlib-ng; do - [ -d "$d" ] && cp -R "$d" "${PKG_DIR}/usr/local/" || true - done - mkdir -p "${PKG_DIR}/usr/local/lib" - cp -R /usr/local/lib/. "${PKG_DIR}/usr/local/lib/" 2>/dev/null || true + cp /usr/sbin/nginx "${pkg_dir}/usr/sbin/" + cp -R /nginx/* "${pkg_dir}/nginx/" || true + cp "${unit_src}" "${pkg_dir}/etc/systemd/system/nginx.service" + cp -R /hostdata/default "${pkg_dir}/hostdata/" || true + cp -R /usr/nginx_lua "${pkg_dir}/usr/" || true - for lib in $(ldd /usr/sbin/nginx | grep '=> /' | awk '{print $3}'); do - case "$lib" in - /usr/local/*) continue ;; - esac - cp "$lib" "${PKG_DIR}/usr/lib/" || true - done + for d in /usr/local/aws-lc /usr/local/LuaJIT /usr/local/modsecurity /usr/local/zlib-ng; do + [ -d "$d" ] && cp -R "$d" "${pkg_dir}/usr/local/" || true + done + mkdir -p "${pkg_dir}/usr/local/lib" + cp -R /usr/local/lib/. "${pkg_dir}/usr/local/lib/" 2>/dev/null || true - mkdir -p "${DEB_DIR}" - cat > "${DEB_DIR}/control" < - Description: Nginx L7 DDoS Protection (The-World-Is-Yours), built by RAWeb CI for ${TARGET}. - EOF + for lib in $(ldd /usr/sbin/nginx | grep '=> /' | awk '{print $3}'); do + case "$lib" in /usr/local/*) continue ;; esac + cp "$lib" "${pkg_dir}/usr/lib/" || true + done - cat > "${DEB_DIR}/postinst" <<'EOFPOSTINST' - #!/bin/bash - useradd -r -s /bin/false nginx 2>/dev/null || true - install -d -o nginx -g nginx -m 0755 /var/log/nginx - # /run/nginx/temp/* is recreated on every systemd start (ExecStartPre) - # since /run is tmpfs and cleared on reboot. - chown -R nginx:nginx /var/log/nginx /nginx 2>/dev/null || true - systemctl daemon-reload 2>/dev/null || true - systemctl enable nginx.service 2>/dev/null || true - systemctl restart nginx.service 2>/dev/null || true - exit 0 - EOFPOSTINST - chmod 755 "${DEB_DIR}/postinst" + mkdir -p "${deb_dir}" + cat > "${deb_dir}/control" < + Description: Nginx L7 DDoS Protection (${pkg_name}), built by RAWeb CI for ${TARGET}. + EOF - dpkg-deb --build "${PKG_DIR}" - DEB_FILE="${PKG_DIR}.deb" + cat > "${deb_dir}/postinst" <<'EOFPOSTINST' + #!/bin/bash + useradd -r -s /bin/false nginx 2>/dev/null || true + install -d -o nginx -g nginx -m 0755 /var/log/nginx + chown -R nginx:nginx /var/log/nginx /nginx 2>/dev/null || true + systemctl daemon-reload 2>/dev/null || true + systemctl enable nginx.service 2>/dev/null || true + systemctl restart nginx.service 2>/dev/null || true + exit 0 + EOFPOSTINST + chmod 755 "${deb_dir}/postinst" + + dpkg-deb --build "${pkg_dir}" + } + + assemble_deb "twiy" "${REPO_ROOT}/static/${DISTRO_DIR}/nginx.service" "twiy-raweb" + assemble_deb "twiy-raweb" "${REPO_ROOT}/static/${DISTRO_DIR}/nginx-raweb.service" "twiy" + + DEB_TWIY="/opt/twiy_${VERSION}_${ARCH}.deb" + DEB_RAWEB="/opt/twiy-raweb_${VERSION}_${ARCH}.deb" { - echo "deb_file=${DEB_FILE}" - echo "version=${VERSION}" - echo "pkg_name=${PKG_NAME}" + echo "deb_twiy=${DEB_TWIY}" + echo "deb_raweb=${DEB_RAWEB}" + echo "version=${VERSION}" } >> "$GITHUB_OUTPUT" - ls -la "${DEB_FILE}" - sha256sum "${DEB_FILE}" + ls -la /opt/twiy*.deb + sha256sum /opt/twiy*.deb - name: Publish env: @@ -124,8 +134,8 @@ jobs: NEXUS_PASS: ${{ secrets[matrix.nexus_pass_secret] }} NEXUS_URL: ${{ secrets.NEXUS_URL }} NEXUS_REPO: ${{ secrets[matrix.nexus_repo_secret] }} - DEB_FILE: ${{ steps.pkg.outputs.deb_file }} - PKG_NAME: ${{ steps.pkg.outputs.pkg_name }} + DEB_TWIY: ${{ steps.pkg.outputs.deb_twiy }} + DEB_RAWEB: ${{ steps.pkg.outputs.deb_raweb }} TARGET: ${{ matrix.target }} run: | set -euo pipefail @@ -137,8 +147,8 @@ jobs: || mktemp -d -t twiy-XXXXXXXX)" chmod 700 "$SECDIR" cleanup() { - find "$SECDIR" -type f -exec shred -uz {} + 2>/dev/null || true - rm -rf "$SECDIR" + find "$SECDIR" -type f -exec shred -uz {} + 2>/dev/null || true + rm -rf "$SECDIR" } trap cleanup EXIT INT TERM HUP @@ -147,24 +157,33 @@ jobs: "$NEXUS_HOST" "$NEXUS_USER" "$NEXUS_PASS" > "$SECDIR/netrc" unset NEXUS_USER NEXUS_PASS - OLD_ID="$(curl -fsS --netrc-file "$SECDIR/netrc" \ - "$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO" \ - | PKG_NAME="$PKG_NAME" python3 -c ' + publish_one() { + local deb="$1" pkg_name="$2" + + local old_id + old_id="$(curl -fsS --netrc-file "$SECDIR/netrc" \ + "$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO" \ + | PKG_NAME="$pkg_name" python3 -c ' import sys, json, os for c in json.load(sys.stdin).get("items", []): if c.get("name") == os.environ["PKG_NAME"]: print(c["id"]); break ' || true)" - if [ -n "$OLD_ID" ]; then - curl -fsS -X DELETE --netrc-file "$SECDIR/netrc" \ - "$NEXUS_URL/service/rest/v1/components/$OLD_ID" -o /dev/null - fi + if [ -n "$old_id" ]; then + curl -fsS -X DELETE --netrc-file "$SECDIR/netrc" \ + "$NEXUS_URL/service/rest/v1/components/$old_id" -o /dev/null + fi - HTTP="$(curl -sS --netrc-file "$SECDIR/netrc" \ - -o "$SECDIR/upload.body" -w '%{http_code}' \ - -X POST -F "apt.asset=@$DEB_FILE" \ - "$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO")" - case "$HTTP" in - 201|204) echo "[$TARGET] uploaded $(basename "$DEB_FILE")" ;; - *) echo "[$TARGET] upload failed (HTTP $HTTP)"; cat "$SECDIR/upload.body"; exit 1 ;; - esac + local http + http="$(curl -sS --netrc-file "$SECDIR/netrc" \ + -o "$SECDIR/upload.body" -w '%{http_code}' \ + -X POST -F "apt.asset=@$deb" \ + "$NEXUS_URL/service/rest/v1/components?repository=$NEXUS_REPO")" + case "$http" in + 201|204) echo "[$TARGET] uploaded $(basename "$deb")" ;; + *) echo "[$TARGET] upload failed for $pkg_name (HTTP $http)"; cat "$SECDIR/upload.body"; exit 1 ;; + esac + } + + publish_one "$DEB_TWIY" "twiy" + publish_one "$DEB_RAWEB" "twiy-raweb" diff --git a/.gitignore b/.gitignore index 9cc89fa..4ca3a5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.claude/ +.claude .codex .env .creds @@ -9,3 +9,4 @@ Dockerfile docker-compose.yaml docker-compose.yml PENDING_*.md +PATCH_*.md diff --git a/README.md b/README.md index 9f50239..ff03f69 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,6 @@ - [x] Cookie-based challenge - [x] [Versions List](https://git.julio.al/theraw/The-World-Is-Yours/src/branch/master/version) -## Easy install - -## CAREFUL - -Raweb-nginx uses custom .service that limits system visibility for security reasons, basically you need to store your data on /hostdata, or /srv, if you use custom folders then you have to edit the service, for more details check : https://github.com/theraw/The-World-Is-Yours/blob/master/static/Trixie/nginx.service - ### Debian 13 (trixie) ```bash sudo install -d /etc/apt/keyrings @@ -33,10 +27,7 @@ echo "deb [signed-by=/etc/apt/keyrings/raweb.asc] https://apt.julio.al/repositor sudo apt update && sudo apt install twiy ``` -## Compile from source - -Pick the script that matches your OS — they're separate so apt package -divergences (e.g. the t64 ABI transition on Ubuntu 24.04+) stay isolated. +## Compile from source by yourself. ```bash apt-get -y install git && cd /root/ && git clone https://git.julio.al/theraw/The-World-Is-Yours.git && cd The-World-Is-Yours/ diff --git a/static/Raccoon/nginx-raweb.service b/static/Raccoon/nginx-raweb.service new file mode 100644 index 0000000..9e3bbcb --- /dev/null +++ b/static/Raccoon/nginx-raweb.service @@ -0,0 +1,70 @@ +[Unit] +Description=A high performance web server and a reverse proxy server (twiy) +After=syslog.target network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target + +[Service] +Type=forking +PIDFile=/run/nginx.pid +Environment=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ExecStartPre=/usr/bin/install -d -o nginx -g nginx -m 0755 /run/nginx/temp /run/nginx/temp/client_body /run/nginx/temp/proxy /run/nginx/temp/fastcgi /run/nginx/temp/uwsgi /run/nginx/temp/scgi /var/log/nginx +ExecStartPre=/usr/sbin/nginx -t +ExecStart=/usr/sbin/nginx -c /nginx/nginx.conf +ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /run/nginx.pid)" +ExecStop=/bin/sh -c "/bin/kill -s QUIT $(/bin/cat /run/nginx.pid)" +TimeoutStartSec=10 +LimitNOFILE=65535 + +# === hardening: deny-everything by default, allowlist via bind mounts === +# TemporaryFileSystem=/ replaces the visible filesystem with an empty tmpfs. +# Everything not bind-mounted below is invisible to nginx workers — even +# read access. Compromise of a worker can no longer enumerate /etc/passwd, +# /home/*, /var/lib/*, /root, /opt, etc. +TemporaryFileSystem=/ + +# Read-only: nginx binary, dynamic linker, all linked libs, system config, +# CA bundles, Let's Encrypt certs (live/ + archive/ both under /etc). +BindReadOnlyPaths=/usr +BindReadOnlyPaths=/lib +BindReadOnlyPaths=/lib64 +BindReadOnlyPaths=/bin +BindReadOnlyPaths=/sbin +BindReadOnlyPaths=/etc + +# Read-write: nginx runtime state. +# /run nginx.pid, nginx.lock, /run/nginx/temp/*, PHP-FPM sock +# /var/log/nginx access.log, error.log +# /nginx config dir (read-mostly but reload writes some state) +BindPaths=/run +BindPaths=/var/log/nginx +BindPaths=/nginx +BindPaths=/var/cache/nginx +BindPaths=/srv +BindPaths=/hostdata +BindPaths=/raweb + +NoNewPrivileges=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +ProtectHostname=true +PrivateDevices=true +PrivateTmp=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK +RestrictNamespaces=true +RestrictRealtime=true +RestrictSUIDSGID=true +LockPersonality=true +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallErrorNumber=EPERM + +# NOTE deliberately OFF: +# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages) +# SystemCallFilter=~@resources breaks nginx workers' prlimit64() +# ProtectSystem and ProtectHome are redundant under TemporaryFileSystem=/. + +[Install] +WantedBy=multi-user.target diff --git a/static/Raccoon/nginx.service b/static/Raccoon/nginx.service index 9e3bbcb..7fc2ad6 100644 --- a/static/Raccoon/nginx.service +++ b/static/Raccoon/nginx.service @@ -15,56 +15,5 @@ ExecStop=/bin/sh -c "/bin/kill -s QUIT $(/bin/cat /run/nginx.pid)" TimeoutStartSec=10 LimitNOFILE=65535 -# === hardening: deny-everything by default, allowlist via bind mounts === -# TemporaryFileSystem=/ replaces the visible filesystem with an empty tmpfs. -# Everything not bind-mounted below is invisible to nginx workers — even -# read access. Compromise of a worker can no longer enumerate /etc/passwd, -# /home/*, /var/lib/*, /root, /opt, etc. -TemporaryFileSystem=/ - -# Read-only: nginx binary, dynamic linker, all linked libs, system config, -# CA bundles, Let's Encrypt certs (live/ + archive/ both under /etc). -BindReadOnlyPaths=/usr -BindReadOnlyPaths=/lib -BindReadOnlyPaths=/lib64 -BindReadOnlyPaths=/bin -BindReadOnlyPaths=/sbin -BindReadOnlyPaths=/etc - -# Read-write: nginx runtime state. -# /run nginx.pid, nginx.lock, /run/nginx/temp/*, PHP-FPM sock -# /var/log/nginx access.log, error.log -# /nginx config dir (read-mostly but reload writes some state) -BindPaths=/run -BindPaths=/var/log/nginx -BindPaths=/nginx -BindPaths=/var/cache/nginx -BindPaths=/srv -BindPaths=/hostdata -BindPaths=/raweb - -NoNewPrivileges=true -ProtectKernelTunables=true -ProtectKernelModules=true -ProtectKernelLogs=true -ProtectControlGroups=true -ProtectClock=true -ProtectHostname=true -PrivateDevices=true -PrivateTmp=true -RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK -RestrictNamespaces=true -RestrictRealtime=true -RestrictSUIDSGID=true -LockPersonality=true -SystemCallArchitectures=native -SystemCallFilter=@system-service -SystemCallErrorNumber=EPERM - -# NOTE deliberately OFF: -# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages) -# SystemCallFilter=~@resources breaks nginx workers' prlimit64() -# ProtectSystem and ProtectHome are redundant under TemporaryFileSystem=/. - [Install] WantedBy=multi-user.target diff --git a/static/Trixie/nginx-raweb.service b/static/Trixie/nginx-raweb.service new file mode 100644 index 0000000..9e3bbcb --- /dev/null +++ b/static/Trixie/nginx-raweb.service @@ -0,0 +1,70 @@ +[Unit] +Description=A high performance web server and a reverse proxy server (twiy) +After=syslog.target network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target + +[Service] +Type=forking +PIDFile=/run/nginx.pid +Environment=LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 +ExecStartPre=/usr/bin/install -d -o nginx -g nginx -m 0755 /run/nginx/temp /run/nginx/temp/client_body /run/nginx/temp/proxy /run/nginx/temp/fastcgi /run/nginx/temp/uwsgi /run/nginx/temp/scgi /var/log/nginx +ExecStartPre=/usr/sbin/nginx -t +ExecStart=/usr/sbin/nginx -c /nginx/nginx.conf +ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /run/nginx.pid)" +ExecStop=/bin/sh -c "/bin/kill -s QUIT $(/bin/cat /run/nginx.pid)" +TimeoutStartSec=10 +LimitNOFILE=65535 + +# === hardening: deny-everything by default, allowlist via bind mounts === +# TemporaryFileSystem=/ replaces the visible filesystem with an empty tmpfs. +# Everything not bind-mounted below is invisible to nginx workers — even +# read access. Compromise of a worker can no longer enumerate /etc/passwd, +# /home/*, /var/lib/*, /root, /opt, etc. +TemporaryFileSystem=/ + +# Read-only: nginx binary, dynamic linker, all linked libs, system config, +# CA bundles, Let's Encrypt certs (live/ + archive/ both under /etc). +BindReadOnlyPaths=/usr +BindReadOnlyPaths=/lib +BindReadOnlyPaths=/lib64 +BindReadOnlyPaths=/bin +BindReadOnlyPaths=/sbin +BindReadOnlyPaths=/etc + +# Read-write: nginx runtime state. +# /run nginx.pid, nginx.lock, /run/nginx/temp/*, PHP-FPM sock +# /var/log/nginx access.log, error.log +# /nginx config dir (read-mostly but reload writes some state) +BindPaths=/run +BindPaths=/var/log/nginx +BindPaths=/nginx +BindPaths=/var/cache/nginx +BindPaths=/srv +BindPaths=/hostdata +BindPaths=/raweb + +NoNewPrivileges=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +ProtectClock=true +ProtectHostname=true +PrivateDevices=true +PrivateTmp=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK +RestrictNamespaces=true +RestrictRealtime=true +RestrictSUIDSGID=true +LockPersonality=true +SystemCallArchitectures=native +SystemCallFilter=@system-service +SystemCallErrorNumber=EPERM + +# NOTE deliberately OFF: +# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages) +# SystemCallFilter=~@resources breaks nginx workers' prlimit64() +# ProtectSystem and ProtectHome are redundant under TemporaryFileSystem=/. + +[Install] +WantedBy=multi-user.target diff --git a/static/Trixie/nginx.service b/static/Trixie/nginx.service index 9e3bbcb..7fc2ad6 100644 --- a/static/Trixie/nginx.service +++ b/static/Trixie/nginx.service @@ -15,56 +15,5 @@ ExecStop=/bin/sh -c "/bin/kill -s QUIT $(/bin/cat /run/nginx.pid)" TimeoutStartSec=10 LimitNOFILE=65535 -# === hardening: deny-everything by default, allowlist via bind mounts === -# TemporaryFileSystem=/ replaces the visible filesystem with an empty tmpfs. -# Everything not bind-mounted below is invisible to nginx workers — even -# read access. Compromise of a worker can no longer enumerate /etc/passwd, -# /home/*, /var/lib/*, /root, /opt, etc. -TemporaryFileSystem=/ - -# Read-only: nginx binary, dynamic linker, all linked libs, system config, -# CA bundles, Let's Encrypt certs (live/ + archive/ both under /etc). -BindReadOnlyPaths=/usr -BindReadOnlyPaths=/lib -BindReadOnlyPaths=/lib64 -BindReadOnlyPaths=/bin -BindReadOnlyPaths=/sbin -BindReadOnlyPaths=/etc - -# Read-write: nginx runtime state. -# /run nginx.pid, nginx.lock, /run/nginx/temp/*, PHP-FPM sock -# /var/log/nginx access.log, error.log -# /nginx config dir (read-mostly but reload writes some state) -BindPaths=/run -BindPaths=/var/log/nginx -BindPaths=/nginx -BindPaths=/var/cache/nginx -BindPaths=/srv -BindPaths=/hostdata -BindPaths=/raweb - -NoNewPrivileges=true -ProtectKernelTunables=true -ProtectKernelModules=true -ProtectKernelLogs=true -ProtectControlGroups=true -ProtectClock=true -ProtectHostname=true -PrivateDevices=true -PrivateTmp=true -RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK -RestrictNamespaces=true -RestrictRealtime=true -RestrictSUIDSGID=true -LockPersonality=true -SystemCallArchitectures=native -SystemCallFilter=@system-service -SystemCallErrorNumber=EPERM - -# NOTE deliberately OFF: -# MemoryDenyWriteExecute=true breaks LuaJIT (JIT writable+executable pages) -# SystemCallFilter=~@resources breaks nginx workers' prlimit64() -# ProtectSystem and ProtectHome are redundant under TemporaryFileSystem=/. - [Install] WantedBy=multi-user.target