diff options
Diffstat (limited to 'infra')
| -rw-r--r-- | infra/Caddyfile | 110 | ||||
| -rw-r--r-- | infra/Caddyfile.local | 42 | ||||
| -rw-r--r-- | infra/chat/build-browser.sh | 34 | ||||
| -rw-r--r-- | infra/chat/build-native.sh | 63 | ||||
| -rwxr-xr-x | infra/chat/build-openssl-wasi.sh | 45 | ||||
| -rw-r--r-- | infra/chat/build-source.sh | 29 | ||||
| -rw-r--r-- | infra/chat/build-typescript.sh | 24 | ||||
| -rw-r--r-- | infra/chat/openssl-wasi.conf | 22 | ||||
| -rw-r--r-- | infra/containers/cgit/.containerignore | 21 | ||||
| -rw-r--r-- | infra/containers/cgit/Containerfile | 27 | ||||
| -rw-r--r-- | infra/containers/cgit/cgitrc | 27 | ||||
| -rw-r--r-- | infra/containers/cgit/entrypoint.sh | 20 | ||||
| -rw-r--r-- | infra/containers/cgit/nginx.conf | 46 | ||||
| -rw-r--r-- | infra/containers/cgit/supervisord.conf | 42 | ||||
| -rw-r--r-- | infra/containers/chat/Containerfile | 27 | ||||
| -rwxr-xr-x | infra/host-setup.sh | 28 | ||||
| -rw-r--r-- | infra/podman.conf | 17 | ||||
| -rw-r--r-- | infra/searxng/settings.yml | 24 | ||||
| -rw-r--r-- | infra/services.toml | 58 | ||||
| -rw-r--r-- | infra/stack.service | 34 |
20 files changed, 740 insertions, 0 deletions
diff --git a/infra/Caddyfile b/infra/Caddyfile new file mode 100644 index 0000000..140101d --- /dev/null +++ b/infra/Caddyfile @@ -0,0 +1,110 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +{ + http_port {{HTTP_PORT}} + https_port {{HTTPS_PORT}} +} + +(https_security) { + header >Strict-Transport-Security "max-age=31536000" +} + +https://{{BASE_DOMAIN}}:{{HTTPS_PORT}} { + import https_security + handle /.well-known/openpgpkey/* { + root * /srv + header Content-Type application/octet-stream + file_server + } + + handle { + redir {{SITE_ORIGIN}}{uri} permanent + } +} + +https://www.{{BASE_DOMAIN}}:{{HTTPS_PORT}} { + import https_security + redir {{SITE_ORIGIN}}{uri} permanent +} + +https://{{SITE_HOST}}:{{HTTPS_PORT}} { + import https_security + redir /message {{CHAT_PUBLIC_ORIGIN}}/ permanent + redir /message/ {{CHAT_PUBLIC_ORIGIN}}/ permanent + root * /srv + file_server + + redir /git /git/ + + handle /cgit* { + reverse_proxy {{CGIT_UPSTREAM}} + } + + handle /git/* { + reverse_proxy {{CGIT_UPSTREAM}} + } +} + +https://{{WKD_HOST}}:{{HTTPS_PORT}} { + import https_security + handle /.well-known/openpgpkey/* { + root * /srv + header Content-Type application/octet-stream + file_server + } +} + +https://{{GIT_HOST}}:{{HTTPS_PORT}} { + import https_security + redir /{path}.git /{path} permanent + + reverse_proxy {{CGIT_UPSTREAM}} +} + +https://{{SEARCH_HOST}}:{{HTTPS_PORT}} { + import https_security + reverse_proxy {{SEARXNG_UPSTREAM}} +} + +https://www.{{SITE_HOST}}:{{HTTPS_PORT}} { + import https_security + redir {{SITE_ORIGIN}}{uri} permanent +} + +https://www.{{GIT_HOST}}:{{HTTPS_PORT}} { + import https_security + redir {{GIT_ORIGIN}}{uri} permanent +} + +https://www.{{SEARCH_HOST}}:{{HTTPS_PORT}} { + import https_security + redir {{SEARCH_ORIGIN}}{uri} permanent +} + +https://www.{{WKD_HOST}}:{{HTTPS_PORT}} { + import https_security + redir {{WKD_ORIGIN}}{uri} permanent +} + +https://{{CHAT_HOST}}:{{HTTPS_PORT}} { + import https_security + reverse_proxy {{CHAT_UPSTREAM}} +} + +https://www.{{CHAT_HOST}}:{{HTTPS_PORT}} { + import https_security + redir {{CHAT_PUBLIC_ORIGIN}}{uri} permanent +} diff --git a/infra/Caddyfile.local b/infra/Caddyfile.local new file mode 100644 index 0000000..94114f9 --- /dev/null +++ b/infra/Caddyfile.local @@ -0,0 +1,42 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +:80 { + redir /message {{CHAT_PUBLIC_ORIGIN}}/ permanent + redir /message/ {{CHAT_PUBLIC_ORIGIN}}/ permanent + redir /git /git/?{query} permanent + redir /search /search/?{query} permanent + @git path /git /git/* /cgit.js /cgit.png + handle @git { + uri strip_prefix /git + reverse_proxy {{CGIT_UPSTREAM}} + } + + @search path /search /search/* + handle @search { + reverse_proxy {{SEARXNG_UPSTREAM}} { + header_up X-Script-Name /search + } + } + + handle { + root * /srv + file_server + } +} + +http://{{CHAT_LOCAL_HOST}}:80 { + reverse_proxy {{CHAT_UPSTREAM}} +} diff --git a/infra/chat/build-browser.sh b/infra/chat/build-browser.sh new file mode 100644 index 0000000..dd0c777 --- /dev/null +++ b/infra/chat/build-browser.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" +SOURCE="$ROOT/.tools/wasi-source" +SDK="$SOURCE/wasi-sdk-34.0-x86_64-linux" +PREFIX="$ROOT/.tools/openssl-wasi" +cd "$ROOT" +test -x "$SDK/bin/clang" +test -f "$PREFIX/lib/libcrypto.a" +printf '%s %s\n' b761e3a0721dbae9c09a0059e5fdb2bf917d1b4a8a7b430fb3b5aafb0984b2c4 "$SOURCE/sdk.tar.gz" | sha256sum --check +printf '%s %s\n' a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98 "$SOURCE/openssl.tar.gz" | sha256sum --check +rustup target add wasm32-wasip1 +RUST_LIB="$(rustc --print target-libdir --target wasm32-wasip1)/self-contained" +env LIBCLANG_PATH="$SDK/lib" OPENSSL_DIR="$PREFIX" OPENSSL_STATIC=1 \ + CC_wasm32_wasip1="$SDK/bin/clang" AR_wasm32_wasip1="$SDK/bin/llvm-ar" \ + BINDGEN_EXTRA_CLANG_ARGS_wasm32_wasip1="--sysroot=$SDK/share/wasi-sysroot --target=wasm32-wasip1 -fvisibility=default" \ + RUSTFLAGS="-Lnative=$RUST_LIB -Lnative=$SDK/share/wasi-sysroot/lib/wasm32-wasip1 -Clink-arg=-lwasi-emulated-getpid -Clink-arg=--max-memory=268435456" \ + cargo build --locked --release -p stack-chat-crypto --bin stack-chat-crypto --target wasm32-wasip1 +sha256sum target/wasm32-wasip1/release/stack-chat-crypto.wasm diff --git a/infra/chat/build-native.sh b/infra/chat/build-native.sh new file mode 100644 index 0000000..f882fef --- /dev/null +++ b/infra/chat/build-native.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" +TOOLS="$ROOT/.tools" +SOURCE="$TOOLS/openssl-native-source" +PREFIX="$TOOLS/openssl-musl" +HEADERS="$TOOLS/alpine/usr/include" +KERNEL="$TOOLS/kernel-headers" +mkdir -p "$SOURCE" "$TOOLS/wasi-source" "$TOOLS/alpine" "$KERNEL" +fetch() { + file="$1" + digest="$2" + url="$3" + if ! test -f "$file"; then + curl --fail --location --retry 2 "$url" --output "$file.download" + printf '%s %s\n' "$digest" "$file.download" | sha256sum --check --status + mv "$file.download" "$file" + fi + printf '%s %s\n' "$digest" "$file" | sha256sum --check +} +fetch "$TOOLS/wasi-source/openssl.tar.gz" a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98 https://github.com/openssl/openssl/releases/download/openssl-3.6.5/openssl-3.6.5.tar.gz +fetch "$TOOLS/musl-dev.apk" 310b51cff12e1d5ce5f135c558a82e2550427da5465bbd16c9ff9b05e63ee3d9 https://dl-cdn.alpinelinux.org/alpine/v3.24/main/x86_64/musl-dev-1.2.6-r3.apk +if ! test -f "$HEADERS/stdio.h"; then tar -xzf "$TOOLS/musl-dev.apk" -C "$TOOLS/alpine" usr/include; fi +if ! test -f "$SOURCE/openssl-3.6.5/Configure"; then tar -xzf "$TOOLS/wasi-source/openssl.tar.gz" -C "$SOURCE"; fi +GCC_INCLUDE="$(cc -print-file-name=include)" +KERNEL_ASM=/usr/include/asm +if ! test -d "$KERNEL_ASM"; then KERNEL_ASM="/usr/include/$(cc -dumpmachine)/asm"; fi +test -f /usr/include/linux/mman.h +test -d "$KERNEL_ASM" +ln -sfn /usr/include/linux "$KERNEL/linux" +ln -sfn "$KERNEL_ASM" "$KERNEL/asm" +ln -sfn /usr/include/asm-generic "$KERNEL/asm-generic" +MUSL_CC="cc -nostdinc -isystem $HEADERS -isystem $GCC_INCLUDE -idirafter $KERNEL" +STAMP="$(sha256sum "$ROOT/infra/chat/build-native.sh" | cut -d' ' -f1)" +if ! test -f "$PREFIX/.stack-build" || ! test "$(cat "$PREFIX/.stack-build")" = "$STAMP"; then + cd "$SOURCE/openssl-3.6.5" + env CC="$MUSL_CC" ./Configure linux-x86_64 no-shared no-module no-dso no-tests no-autoload-config --with-rand-seed=getrandom --prefix="$PREFIX" --libdir=lib + make -j"${CHAT_BUILD_JOBS:-8}" build_libs + make install_dev + printf '%s\n' "$STAMP" > "$PREFIX/.stack-build" +fi +cd "$ROOT" +rustup target add x86_64-unknown-linux-musl +env OPENSSL_DIR="$PREFIX" OPENSSL_STATIC=1 CC_x86_64_unknown_linux_musl="$MUSL_CC" \ + BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_musl="-nostdinc -isystem $HEADERS -isystem $GCC_INCLUDE -idirafter $KERNEL" \ + cargo build --locked --release --target x86_64-unknown-linux-musl -p stack -p stack-chat-server -p stack-chat-crypto +"$ROOT/target/x86_64-unknown-linux-musl/release/stack-chat-crypto" +file "$ROOT/target/x86_64-unknown-linux-musl/release/stack-chat-server" diff --git a/infra/chat/build-openssl-wasi.sh b/infra/chat/build-openssl-wasi.sh new file mode 100755 index 0000000..91c0583 --- /dev/null +++ b/infra/chat/build-openssl-wasi.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" +SOURCE="$ROOT/.tools/wasi-source" +SDK="$SOURCE/wasi-sdk-34.0-x86_64-linux" +PREFIX="$ROOT/.tools/openssl-wasi" +mkdir -p "$SOURCE" + +fetch() { + file="$1" + digest="$2" + url="$3" + if ! test -f "$file"; then + curl --fail --location --retry 2 "$url" --output "$file.download" + printf '%s %s\n' "$digest" "$file.download" | sha256sum --check --status + mv "$file.download" "$file" + fi + printf '%s %s\n' "$digest" "$file" | sha256sum --check +} + +fetch "$SOURCE/sdk.tar.gz" b761e3a0721dbae9c09a0059e5fdb2bf917d1b4a8a7b430fb3b5aafb0984b2c4 https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-linux.tar.gz +fetch "$SOURCE/openssl.tar.gz" a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98 https://github.com/openssl/openssl/releases/download/openssl-3.6.5/openssl-3.6.5.tar.gz +if ! test -x "$SDK/bin/clang"; then tar -xzf "$SOURCE/sdk.tar.gz" -C "$SOURCE"; fi +if ! test -f "$SOURCE/openssl-3.6.5/Configure"; then tar -xzf "$SOURCE/openssl.tar.gz" -C "$SOURCE"; fi +cp "$ROOT/infra/chat/openssl-wasi.conf" "$SOURCE/openssl-3.6.5/Configurations/99-stack-wasi.conf" +cd "$SOURCE/openssl-3.6.5" +env CC="$SDK/bin/clang" AR="$SDK/bin/llvm-ar" RANLIB="$SDK/bin/llvm-ranlib" CFLAGS='-O2 -D_WASI_EMULATED_GETPID -Dgetuid=getpagesize -Dgeteuid=getpagesize -Dgetgid=getpagesize -Dgetegid=getpagesize' LDFLAGS='-lwasi-emulated-getpid' ./Configure stack-wasi --prefix="$PREFIX" --libdir=lib --with-rand-seed=getrandom no-asm no-async no-autoload-config no-dso no-module no-posix-io no-secure-memory no-shared no-sock no-stdio no-thread-pool no-threads no-ui-console +make -j"${CHAT_BUILD_JOBS:-8}" build_libs +make install_dev +sh "$ROOT/infra/chat/build-browser.sh" diff --git a/infra/chat/build-source.sh b/infra/chat/build-source.sh new file mode 100644 index 0000000..475b519 --- /dev/null +++ b/infra/chat/build-source.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" +cd "$ROOT" +BUILD="$ROOT/var/build" +mkdir -p "$BUILD" +cargo vendor --locked var/build/chat-vendor | sed 's|directory = "var/build/chat-vendor"|directory = "chat-vendor"|' > "$BUILD/chat-vendor-config.txt" +cp "$ROOT/.tools/wasi-source/openssl.tar.gz" "$BUILD/chat-openssl-3.6.5.tar.gz" +printf '%s %s\n' a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98 "$BUILD/chat-openssl-3.6.5.tar.gz" | sha256sum --check +source_list="$BUILD/chat-source-files.txt" +find clippy.toml eslint.config.ts package.json package-lock.json tsconfig.json tsconfig.browser.json tsconfig.worker.json tsconfig.tests.json tsconfig.tools.json tests Cargo.toml Cargo.lock rust-toolchain.toml .cargo .gitignore .gitattributes src crates infra web docs README.txt LICENSE deny.toml about.toml about.hbs .env.example -type f -print > "$source_list" +tar -czf "$BUILD/chat-source.tar.gz.pending" --verbatim-files-from -T "$source_list" -C "$BUILD" chat-vendor chat-vendor-config.txt chat-openssl-3.6.5.tar.gz +mv "$BUILD/chat-source.tar.gz.pending" "$BUILD/chat-source.tar.gz" +sha256sum "$BUILD/chat-source.tar.gz" diff --git a/infra/chat/build-typescript.sh b/infra/chat/build-typescript.sh new file mode 100644 index 0000000..14cae95 --- /dev/null +++ b/infra/chat/build-typescript.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" +cd "$ROOT" +npm ci --ignore-scripts --no-audit --no-fund --cache "$ROOT/.tools/npm-cache" +npm run check +node node_modules/typescript-native/bin/tsc -p tsconfig.browser.json +node node_modules/typescript-native/bin/tsc -p tsconfig.worker.json +node node_modules/typescript-native/bin/tsc -p tsconfig.tests.json diff --git a/infra/chat/openssl-wasi.conf b/infra/chat/openssl-wasi.conf new file mode 100644 index 0000000..479adee --- /dev/null +++ b/infra/chat/openssl-wasi.conf @@ -0,0 +1,22 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +my %targets = ( + "stack-wasi" => { + inherit_from => [ "BASE_unix" ], + lib_cppflags => add("-DL_ENDIAN"), + bn_ops => "THIRTY_TWO_BIT", + }, +); diff --git a/infra/containers/cgit/.containerignore b/infra/containers/cgit/.containerignore new file mode 100644 index 0000000..4fb13e4 --- /dev/null +++ b/infra/containers/cgit/.containerignore @@ -0,0 +1,21 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +* +!Containerfile +!entrypoint.sh +!nginx.conf +!supervisord.conf +!cgitrc diff --git a/infra/containers/cgit/Containerfile b/infra/containers/cgit/Containerfile new file mode 100644 index 0000000..3bd130a --- /dev/null +++ b/infra/containers/cgit/Containerfile @@ -0,0 +1,27 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +FROM docker.io/library/debian:trixie-slim@sha256:1e1a22175fbf1b32157ddaf0219e1db4e5401fab2b94ed285add64d18587cd2d +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + cgit fcgiwrap nginx-light supervisor curl ca-certificates git \ + && rm -rf /var/lib/apt/lists/* /etc/nginx/sites-enabled/default +COPY nginx.conf /etc/nginx/nginx.conf +COPY supervisord.conf /etc/supervisor/stack.conf +COPY cgitrc /etc/cgitrc +COPY entrypoint.sh /usr/local/bin/stack-cgit +RUN chmod 755 /usr/local/bin/stack-cgit +EXPOSE 8080 +ENTRYPOINT ["/usr/local/bin/stack-cgit"] diff --git a/infra/containers/cgit/cgitrc b/infra/containers/cgit/cgitrc new file mode 100644 index 0000000..fb9cae8 --- /dev/null +++ b/infra/containers/cgit/cgitrc @@ -0,0 +1,27 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +root-title=Doan Luu Duc Tai's repositories +root-desc=Personal git repos +virtual-root=/ +clone-prefix={{GIT_ORIGIN}} +css=/cgit.css +favicon=/favicon.ico +remove-suffix=1 +defbranch=main +cache-root=/var/cache/cgit +cache-size=1000 +cache-scanrc-ttl=1 +scan-path=/srv/git diff --git a/infra/containers/cgit/entrypoint.sh b/infra/containers/cgit/entrypoint.sh new file mode 100644 index 0000000..5de3a06 --- /dev/null +++ b/infra/containers/cgit/entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +mkdir -p /run/fcgiwrap /var/cache/cgit +chown www-data:www-data /run/fcgiwrap /var/cache/cgit +exec /usr/bin/supervisord -n -c /etc/supervisor/stack.conf diff --git a/infra/containers/cgit/nginx.conf b/infra/containers/cgit/nginx.conf new file mode 100644 index 0000000..df50345 --- /dev/null +++ b/infra/containers/cgit/nginx.conf @@ -0,0 +1,46 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +user www-data; +worker_processes auto; +pid /run/nginx.pid; +error_log /dev/stderr warn; +events { worker_connections 1024; } +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log /dev/stdout; + map $http_x_forwarded_proto $cgi_https { + default ""; + https on; + } + server { + listen 8080; + server_name _; + root /usr/share/cgit; + location ~* ^/(cgit\.(css|png|js)|favicon\.ico|robots\.txt)$ { + expires 30d; + } + location / { + include /etc/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $http_host; + fastcgi_param HTTPS $cgi_https; + fastcgi_pass unix:/run/fcgiwrap/socket; + } + } +} diff --git a/infra/containers/cgit/supervisord.conf b/infra/containers/cgit/supervisord.conf new file mode 100644 index 0000000..1a93bb5 --- /dev/null +++ b/infra/containers/cgit/supervisord.conf @@ -0,0 +1,42 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +[supervisord] +nodaemon=true +user=root +logfile=/dev/null +pidfile=/run/supervisord.pid + +[program:fcgiwrap] +command=/usr/sbin/fcgiwrap -f -s unix:/run/fcgiwrap/socket +user=www-data +umask=0007 +autorestart=true +stopasgroup=true +killasgroup=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/fd/2 +stderr_logfile_maxbytes=0 + +[program:nginx] +command=/usr/sbin/nginx -g "daemon off;" +autorestart=true +stopasgroup=true +killasgroup=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/fd/2 +stderr_logfile_maxbytes=0 diff --git a/infra/containers/chat/Containerfile b/infra/containers/chat/Containerfile new file mode 100644 index 0000000..31724b5 --- /dev/null +++ b/infra/containers/chat/Containerfile @@ -0,0 +1,27 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +FROM scratch +COPY server /app/bin/server +COPY crypto.wasm /app/bin/chat/crypto.wasm +COPY SOURCE.tar.gz /app/bin/chat/SOURCE.tar.gz +COPY web /app/bin/chat/web +COPY wasi.mjs /app/bin/chat/wasi.mjs +COPY CHAT-APPLICATION.txt /app/docs/CHAT-APPLICATION.txt +COPY CHAT-PRODUCTION.txt /app/docs/CHAT-PRODUCTION.txt +COPY LICENSE /app/LICENSE +WORKDIR /app +EXPOSE 8080 +ENTRYPOINT ["/app/bin/server", "--root", "/app", "--proxy"] diff --git a/infra/host-setup.sh b/infra/host-setup.sh new file mode 100755 index 0000000..e73645b --- /dev/null +++ b/infra/host-setup.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +set -eu +[ "$(id -u)" = 0 ] || { echo 'Run this script through sudo.' >&2; exit 1; } +id ops >/dev/null +apt-get update +apt-get install -y --no-install-recommends podman uidmap passt slirp4netns fuse-overlayfs netavark aardvark-dns +awk -F: '$1 == "ops" && $3 >= 65536 { found=1 } END { exit !found }' /etc/subuid +awk -F: '$1 == "ops" && $3 >= 65536 { found=1 } END { exit !found }' /etc/subgid +install -d -m 755 /etc/sysctl.d +printf '%s\n' 'net.ipv4.ip_unprivileged_port_start=80' > /etc/sysctl.d/90-stack-rootless-ports.conf +sysctl -p /etc/sysctl.d/90-stack-rootless-ports.conf +loginctl enable-linger ops +printf '%s\n' 'Podman prerequisites ready. Existing production services remain running.' diff --git a/infra/podman.conf b/infra/podman.conf new file mode 100644 index 0000000..5e6965d --- /dev/null +++ b/infra/podman.conf @@ -0,0 +1,17 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +[network] +default_rootless_network_cmd = "slirp4netns" diff --git a/infra/searxng/settings.yml b/infra/searxng/settings.yml new file mode 100644 index 0000000..f8f7d6b --- /dev/null +++ b/infra/searxng/settings.yml @@ -0,0 +1,24 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +use_default_settings: true + +server: + limiter: true + public_instance: false + +search: + formats: + - html diff --git a/infra/services.toml b/infra/services.toml new file mode 100644 index 0000000..7fea853 --- /dev/null +++ b/infra/services.toml @@ -0,0 +1,58 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +format = 1 + +[services.caddy] +image = "docker.io/library/caddy:2-alpine@sha256:5f5c8640aae01df9654968d946d8f1a56c497f1dd5c5cda4cf95ab7c14d58648" +gateway = true +health = ["caddy", "validate", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] +mounts = [ + { source = "@caddy", target = "/etc/caddy/Caddyfile", read_only = true }, + { source = "var/data/caddy/data", target = "/data" }, + { source = "var/data/caddy/config", target = "/config" }, + { source = "@web", target = "/srv", read_only = true }, +] + +[services.cgit] +image = "localhost/stack-cgit:0.1.0" +build = "infra/containers/cgit" +health = ["curl", "--fail", "--silent", "--max-time", "3", "http://127.0.0.1:8080/"] +mounts = [ + { source = "var/data/repos", target = "/srv/git", read_only = true }, + { source = "@cgit", target = "/etc/cgitrc", read_only = true }, +] +tmpfs = ["/run", "/var/cache/cgit"] + +[services.searxng] +image = "docker.io/searxng/searxng:latest@sha256:1dab138ea70a8ceb4d1c182f5c8f256088406c1742b99e279976157dbe1e9759" +environment = ["SEARXNG_SECRET"] +drop_capabilities = true +health = ["wget", "--quiet", "--spider", "http://127.0.0.1:8080/"] +mounts = [ + { source = "var/data/searxng", target = "/etc/searxng" }, +] +tmpfs = ["/var/cache/searxng:mode=1777"] + +[services.chat] +image = "localhost/stack-chat:0.1.0" +build = "bin/chat" +drop_capabilities = true +read_only = true +health = ["/app/bin/server", "--root", "/app", "--proxy", "--healthcheck"] +environment = ["CHAT_SETUP_TOKEN"] +mounts = [ + { source = "@chat", target = "/app/var/data/chat" }, +] diff --git a/infra/stack.service b/infra/stack.service new file mode 100644 index 0000000..702da97 --- /dev/null +++ b/infra/stack.service @@ -0,0 +1,34 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +[Unit] +Description=Personal web stack +Wants=network-online.target +After=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=yes +KillMode=process +WorkingDirectory=%h/stack +ExecStart=%h/stack/bin/stack up --production +ExecStop=%h/stack/bin/stack down +TimeoutStartSec=300 +TimeoutStopSec=120 +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=default.target |
