diff --git a/.env.example b/.env.example index 93f995b..b8a0b73 100644 --- a/.env.example +++ b/.env.example @@ -16,3 +16,16 @@ SSH_PORT=${SSH_PORT} SSH_HOST=${SSH_HOST} SSH_KEY="${SSH_KEY}" SSH_KNOWN_HOST="${SSH_KNOWN_HOST}" +WIREGUARD_ALLOWED_IPS=${WIREGUARD_ALLOWED_IPS} +DNS_SERVER=${DNS_SERVER} +DNS_ADDRESS=${DNS_ADDRESS} +WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY} +WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES} +WIREGUARD_PUBLIC_KEY=${WIREGUARD_PUBLIC_KEY} +WIREGUARD_ENDPOINT_HOST=${WIREGUARD_ENDPOINT_HOST} +WIREGUARD_ENDPOINT_PORT=${WIREGUARD_ENDPOINT_PORT} +WIREGUARD_ENDPOINT_IP=${WIREGUARD_ENDPOINT_IP} +HEALTH_TARGET_ADDRESSES=${HEALTH_TARGET_ADDRESSES} +HEALTH_ICMP_TARGET_IPS=${HEALTH_ICMP_TARGET_IPS} +VERSION_INFORMATION=${VERSION_INFORMATION} +PUBLICIP_ENABLED=${PUBLICIP_ENABLED} diff --git a/.forgejo/workflows/build-and-deploy.yml b/.forgejo/workflows/build-and-deploy.yml index 7396a1f..274e94a 100644 --- a/.forgejo/workflows/build-and-deploy.yml +++ b/.forgejo/workflows/build-and-deploy.yml @@ -10,43 +10,56 @@ jobs: steps: - name: Install dependencies run: | - apt-get update && apt-get install gettext -y + apt-get update && apt-get install gettext dnsutils iputils-ping -y - name: Check out repository uses: actions/checkout@v4 - # - name: Expose repo secrets and vars as shell variables - # env: - # SECRETS_CONTEXT: ${{ toJSON(secrets) }} - # VARS_CONTEXT: ${{ toJSON(vars) }} - # run: | - # # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable - # # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings - # # # EOF randomness is to account for empty secrets and vars - # EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) - # to_envs() { jq -r "to_entries[] | \"\(.key)<<$EOF\n\(.value)\n$EOF\n\""; } - # echo "$VARS_CONTEXT" | to_envs >> $GITHUB_ENV - # echo "$SECRETS_CONTEXT" | to_envs >> $GITHUB_ENV - name: Substitute environment variables in .env.example and write to .env env: CERTBOT_EMAIL: ${{secrets.CERTBOT_EMAIL}} CLOUDFLARE_API_TOKEN: ${{secrets.CLOUDFLARE_API_TOKEN}} - DOMAIN: ${{secrets.DOMAIN}} - PUBLIC_IP: ${{secrets.PUBLIC_IP}} - ANDROID_SMS_GATEWAY_IP: ${{secrets.ANDROID_SMS_GATEWAY_IP}} - ANDROID_SMS_GATEWAY_URL: ${{secrets.ANDROID_SMS_GATEWAY_URL}} ANDROID_SMS_GATEWAY_LOGIN: ${{secrets.ANDROID_SMS_GATEWAY_LOGIN}} ANDROID_SMS_GATEWAY_PASSWORD: ${{secrets.ANDROID_SMS_GATEWAY_PASSWORD}} ANDROID_SMS_GATEWAY_RECIPIENT_PHONE: ${{secrets.ANDROID_SMS_GATEWAY_RECIPIENT_PHONE}} - ASTRO_DB_REMOTE_URL: ${{secrets.ASTRO_DB_REMOTE_URL}} OTP_SUPER_SECRET_SALT: ${{secrets.OTP_SUPER_SECRET_SALT}} - IMAGE_FILENAME: ${{secrets.IMAGE_FILENAME}} - IMAGE_NAME: ${{secrets.IMAGE_NAME}} SSH_USER: ${{secrets.SSH_USER}} - SSH_PORT: ${{secrets.SSH_PORT}} - SSH_HOST: ${{secrets.SSH_HOST}} - SSH_KEY: ${{secrets.SSH_KEY}} SSH_KNOWN_HOST: ${{secrets.SSH_KNOWN_HOST}} + ASTRO_DB_REMOTE_URL: ${{secrets.ASTRO_DB_REMOTE_URL}} + SSH_KEY: ${{secrets.SSH_KEY}} + WIREGUARD_PRIVATE_KEY: ${{secrets.WIREGUARD_PRIVATE_KEY}} + WIREGUARD_PUBLIC_KEY: ${{secrets.WIREGUARD_PUBLIC_KEY}} + DNS_SERVER: ${{vars.DNS_SERVER}} + DNS_ADDRESS: ${{vars.DNS_ADDRESS}} + DOMAIN: ${{vars.DOMAIN}} + PUBLIC_IP: ${{vars.PUBLIC_IP}} + ANDROID_SMS_GATEWAY_IP: ${{vars.ANDROID_SMS_GATEWAY_IP}} + ANDROID_SMS_GATEWAY_URL: ${{vars.ANDROID_SMS_GATEWAY_URL}} + IMAGE_FILENAME: ${{vars.IMAGE_FILENAME}} + IMAGE_NAME: ${{vars.IMAGE_NAME}} + SSH_PORT: ${{vars.SSH_PORT}} + SSH_HOST: ${{vars.SSH_HOST}} + WIREGUARD_ALLOWED_IPS: ${{vars.WIREGUARD_ALLOWED_IPS}} + WIREGUARD_ADDRESSES: ${{vars.WIREGUARD_ADDRESSES}} + WIREGUARD_ENDPOINT_HOST: ${{vars.WIREGUARD_ENDPOINT_HOST}} + WIREGUARD_ENDPOINT_PORT: ${{vars.WIREGUARD_ENDPOINT_PORT}} + HEALTH_TARGET_ADDRESSES: ${{vars.HEALTH_TARGET_ADDRESSES}} + HEALTH_ICMP_TARGET_IPS: ${{vars.HEALTH_ICMP_TARGET_IPS}} + VERSION_INFORMATION: ${{vars.VERSION_INFORMATION}} + PUBLICIP_ENABLED: ${{vars.PUBLICIP_ENABLED}} run: | envsubst < .env.example > .env + # - name: Export secrets and variables to $GITHUB_ENV + # env: + # SECRETS_CONTEXT: ${{ toJSON(secrets) }} + # VARS_CONTEXT: ${{ toJSON(vars) }} + # run: | + # EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + # to_envs() { jq -r "to_entries[] | \"\(.key)<<$EOF\n\(.value)\n$EOF\n\""; } + # echo "$VARS_CONTEXT" | to_envs >> $GITHUB_ENV + # echo "$SECRETS_CONTEXT" | to_envs >> $GITHUB_ENV + # - name: Update .env with secrets and variables + # run: | + # envsubst < .env.example > .env + # cat .env - name: Run build script run: | cd cicd/scripts diff --git a/astro.config.mjs b/astro.config.mjs index e98b414..427afd4 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -18,12 +18,13 @@ export default defineConfig({ }), // adapter: bun(), // output: "static", + compressHTML: false, devToolbar: { enabled: false }, prefetch: { prefetchAll: true, }, security: { - checkOrigin: true, + checkOrigin: false, }, session: { driver: "lru-cache", diff --git a/bun.lockb b/bun.lockb index 0cc7456..a4e562f 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/cicd/scripts/build.sh b/cicd/scripts/build.sh index 3dedac4..8c105a4 100755 --- a/cicd/scripts/build.sh +++ b/cicd/scripts/build.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -eu ####################### # VARIABLES # diff --git a/cicd/scripts/deploy.sh b/cicd/scripts/deploy.sh index 350fa0a..2dec7ad 100755 --- a/cicd/scripts/deploy.sh +++ b/cicd/scripts/deploy.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -eu ####################### # VARIABLES # @@ -16,7 +17,7 @@ echo "${SSH_KNOWN_HOST}" > ${HOME}/.ssh/known_hosts-${SSH_HOST//./_} chmod -R 600 ${HOME}/.ssh/ chmod 700 ${HOME}/.ssh -grep -q "Host ${SSH_HOST}" ${HOME}/.ssh/config || cat >> ${HOME}/.ssh/config <&1 1>/dev/null || cat >> ${HOME}/.ssh/config <&2 && exit 1 +echo "WIREGUARD_ENDPOINT_IP=${WIREGUARD_ENDPOINT_IP}" >> .env + DOCKER_HOST=ssh://${SSH_HOST} docker load -i ${IMAGE_FILENAME} ssh ${SSH_HOST} "mkdir -p /srv/${IMAGE_NAME#*/}/" diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index b5dd6a4..ab1a62f 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -3,8 +3,8 @@ services: image: ${IMAGE_NAME}:latest restart: always container_name: badblocks-personal-site - ports: - - "4321:4321" + volumes: + - /srv/badblocks-personal-site/db:/db networks: - proxynet env_file: @@ -24,32 +24,33 @@ services: # timeout: 15s # retries: 3 # start_period: 120s - # wireguard: - # image: qmcgaw/gluetun - # cap_add: - # - NET_ADMIN - # container_name: wireguard - # environment: - # - VPN_SERVICE_PROVIDER=custom - # - VPN_TYPE=wireguard - # - HTTPPROXY=on - # expose: - # - "8888" - # env_file: - # - .env - # devices: - # - /dev/net/tun:/dev/net/tun - # restart: unless-stopped - # networks: - # - proxynet + wireguard: + image: qmcgaw/gluetun + cap_add: + - NET_ADMIN + container_name: wireguard + environment: + - VPN_SERVICE_PROVIDER=custom + - VPN_TYPE=wireguard + - HTTPPROXY=on + expose: + - "8888" + env_file: + - .env + devices: + - /dev/net/tun:/dev/net/tun + restart: unless-stopped + networks: + - proxynet # healthcheck: - # test: ss["CMD", "ping", "-c", "1", "-W", "3", "$$ANDROID_SMS_GATEWAY_IP"] + # test: ["CMD", "ping", "-c", "1", "-W", "3", "$$ANDROID_SMS_GATEWAY_IP"] # interval: 30s # timeout: 15s # retries: 3 # start_period: 60s certbot: image: serversideup/certbot-dns-cloudflare + container_name: certbot volumes: - ./certs:/etc/letsencrypt environment: diff --git a/package.json b/package.json index ea5cbff..b99ae72 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,10 @@ "astro-htmx": "^1.0.6", "htmx.org": "^2.0.8", "iconify-icon": "^3.0.2", + "ofetch": "^1.5.1", "otplib": "^12.0.1", "typescript": "^5.9.3", + "undici": "^7.21.0", "validator": "^13.15.26" }, "devDependencies": { diff --git a/src/lib/HttpFetchClient.ts b/src/lib/HttpFetchClient.ts index 54e637c..0b3e7f1 100644 --- a/src/lib/HttpFetchClient.ts +++ b/src/lib/HttpFetchClient.ts @@ -1,43 +1,53 @@ +import { ofetch } from "ofetch"; +import { ProxyAgent } from "undici"; + +const wireguardDispatcher = new ProxyAgent("http://wireguard:8888"); + const httpFetchClient = { get: async (url: string, headers: Record) => { - const response = await fetch(url, { + const response = await ofetch(url, { method: "GET", headers, + dispatcher: wireguardDispatcher, }); return response.json(); }, post: async (url: string, body: JSON, headers: Record) => { - const response = await fetch(url, { + const response = await ofetch(url, { method: "POST", headers, body: JSON.stringify(body), + dispatcher: wireguardDispatcher, }); return response.json(); }, put: async (url: string, body: JSON, headers: Record) => { - const response = await fetch(url, { + const response = await ofetch(url, { method: "PUT", headers, body: JSON.stringify(body), + dispatcher: wireguardDispatcher, }); return response.json(); }, patch: async (url: string, body: JSON, headers: Record) => { - const response = await fetch(url, { + const response = await ofetch(url, { method: "PATCH", headers, body: JSON.stringify(body), + dispatcher: wireguardDispatcher, }); return response.json(); }, delete: async (url: string, headers: Record) => { - const response = await fetch(url, { + const response = await ofetch(url, { method: "DELETE", headers, + dispatcher: wireguardDispatcher, }); return response.json(); diff --git a/src/pages/cap/challenge.ts b/src/pages/cap/challenge.ts index 35151b2..3dde79a 100644 --- a/src/pages/cap/challenge.ts +++ b/src/pages/cap/challenge.ts @@ -4,13 +4,16 @@ export const prerender = false; export const POST: APIRoute = async () => { try { + return new Response(JSON.stringify(await cap.createChallenge()), { + status: 200, + }); + } catch (error) { return new Response( - JSON.stringify(await cap.createChallenge({ challengeDifficulty: 4 })), - { - status: 200, - }, + JSON.stringify({ + success: false, + error: error instanceof Error ? error.message : String(error), + }), + { status: 400 }, ); - } catch { - return new Response(JSON.stringify({ success: false }), { status: 400 }); } };