Enable WireGuard service, change HTTPFetchClient to use wireguard proxy, and add required env vars
All checks were successful
Build And Deploy / build-and-deploy (push) Successful in 1m22s

Add WireGuard-related env variables to .env.example (addresses,
keys, endpoint, DNS)
Resolve WIREGUARD_ENDPOINT_HOST to WIREGUARD_ENDPOINT_IP in
cicd/scripts/deploy.sh and write it to .env, failing if unresolved
Un-comment and enable the wireguard service in docker-compose.yml
Remove an obsolete commented workflow snippet
This commit is contained in:
badblocks 2026-02-05 10:27:26 -08:00
parent 3b64839cbd
commit 1fbcbf772a
No known key found for this signature in database
10 changed files with 106 additions and 57 deletions

View file

@ -16,3 +16,16 @@ SSH_PORT=${SSH_PORT}
SSH_HOST=${SSH_HOST} SSH_HOST=${SSH_HOST}
SSH_KEY="${SSH_KEY}" SSH_KEY="${SSH_KEY}"
SSH_KNOWN_HOST="${SSH_KNOWN_HOST}" 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}

View file

@ -10,43 +10,56 @@ jobs:
steps: steps:
- name: Install dependencies - name: Install dependencies
run: | run: |
apt-get update && apt-get install gettext -y apt-get update && apt-get install gettext dnsutils iputils-ping -y
- name: Check out repository - name: Check out repository
uses: actions/checkout@v4 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 - name: Substitute environment variables in .env.example and write to .env
env: env:
CERTBOT_EMAIL: ${{secrets.CERTBOT_EMAIL}} CERTBOT_EMAIL: ${{secrets.CERTBOT_EMAIL}}
CLOUDFLARE_API_TOKEN: ${{secrets.CLOUDFLARE_API_TOKEN}} 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_LOGIN: ${{secrets.ANDROID_SMS_GATEWAY_LOGIN}}
ANDROID_SMS_GATEWAY_PASSWORD: ${{secrets.ANDROID_SMS_GATEWAY_PASSWORD}} ANDROID_SMS_GATEWAY_PASSWORD: ${{secrets.ANDROID_SMS_GATEWAY_PASSWORD}}
ANDROID_SMS_GATEWAY_RECIPIENT_PHONE: ${{secrets.ANDROID_SMS_GATEWAY_RECIPIENT_PHONE}} 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}} 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_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}} 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: | run: |
envsubst < .env.example > .env 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 - name: Run build script
run: | run: |
cd cicd/scripts cd cicd/scripts

View file

@ -18,12 +18,13 @@ export default defineConfig({
}), }),
// adapter: bun(), // adapter: bun(),
// output: "static", // output: "static",
compressHTML: false,
devToolbar: { enabled: false }, devToolbar: { enabled: false },
prefetch: { prefetch: {
prefetchAll: true, prefetchAll: true,
}, },
security: { security: {
checkOrigin: true, checkOrigin: false,
}, },
session: { session: {
driver: "lru-cache", driver: "lru-cache",

BIN
bun.lockb

Binary file not shown.

View file

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
set -eu
####################### #######################
# VARIABLES # # VARIABLES #

View file

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
set -eu
####################### #######################
# VARIABLES # # VARIABLES #
@ -16,7 +17,7 @@ echo "${SSH_KNOWN_HOST}" > ${HOME}/.ssh/known_hosts-${SSH_HOST//./_}
chmod -R 600 ${HOME}/.ssh/ chmod -R 600 ${HOME}/.ssh/
chmod 700 ${HOME}/.ssh chmod 700 ${HOME}/.ssh
grep -q "Host ${SSH_HOST}" ${HOME}/.ssh/config || cat >> ${HOME}/.ssh/config <<EOF grep -q "Host ${SSH_HOST}" ${HOME}/.ssh/config 2>&1 1>/dev/null || cat >> ${HOME}/.ssh/config <<EOF
Host ${SSH_HOST} Host ${SSH_HOST}
HostName ${SSH_HOST} HostName ${SSH_HOST}
User ${SSH_USER} User ${SSH_USER}
@ -32,6 +33,10 @@ Host ${SSH_HOST}
ServerAliveInterval 10 ServerAliveInterval 10
EOF EOF
WIREGUARD_ENDPOINT_IP=$(dig +short $WIREGUARD_ENDPOINT_HOST | tail -n1)
[[ -z ${WIREGUARD_ENDPOINT_IP} ]] && echo "Failed to resolve IP address for WIREGUARD_ENDPOINT_HOST" >&2 && exit 1
echo "WIREGUARD_ENDPOINT_IP=${WIREGUARD_ENDPOINT_IP}" >> .env
DOCKER_HOST=ssh://${SSH_HOST} docker load -i ${IMAGE_FILENAME} DOCKER_HOST=ssh://${SSH_HOST} docker load -i ${IMAGE_FILENAME}
ssh ${SSH_HOST} "mkdir -p /srv/${IMAGE_NAME#*/}/" ssh ${SSH_HOST} "mkdir -p /srv/${IMAGE_NAME#*/}/"

View file

@ -3,8 +3,8 @@ services:
image: ${IMAGE_NAME}:latest image: ${IMAGE_NAME}:latest
restart: always restart: always
container_name: badblocks-personal-site container_name: badblocks-personal-site
ports: volumes:
- "4321:4321" - /srv/badblocks-personal-site/db:/db
networks: networks:
- proxynet - proxynet
env_file: env_file:
@ -24,32 +24,33 @@ services:
# timeout: 15s # timeout: 15s
# retries: 3 # retries: 3
# start_period: 120s # start_period: 120s
# wireguard: wireguard:
# image: qmcgaw/gluetun image: qmcgaw/gluetun
# cap_add: cap_add:
# - NET_ADMIN - NET_ADMIN
# container_name: wireguard container_name: wireguard
# environment: environment:
# - VPN_SERVICE_PROVIDER=custom - VPN_SERVICE_PROVIDER=custom
# - VPN_TYPE=wireguard - VPN_TYPE=wireguard
# - HTTPPROXY=on - HTTPPROXY=on
# expose: expose:
# - "8888" - "8888"
# env_file: env_file:
# - .env - .env
# devices: devices:
# - /dev/net/tun:/dev/net/tun - /dev/net/tun:/dev/net/tun
# restart: unless-stopped restart: unless-stopped
# networks: networks:
# - proxynet - proxynet
# healthcheck: # 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 # interval: 30s
# timeout: 15s # timeout: 15s
# retries: 3 # retries: 3
# start_period: 60s # start_period: 60s
certbot: certbot:
image: serversideup/certbot-dns-cloudflare image: serversideup/certbot-dns-cloudflare
container_name: certbot
volumes: volumes:
- ./certs:/etc/letsencrypt - ./certs:/etc/letsencrypt
environment: environment:

View file

@ -30,8 +30,10 @@
"astro-htmx": "^1.0.6", "astro-htmx": "^1.0.6",
"htmx.org": "^2.0.8", "htmx.org": "^2.0.8",
"iconify-icon": "^3.0.2", "iconify-icon": "^3.0.2",
"ofetch": "^1.5.1",
"otplib": "^12.0.1", "otplib": "^12.0.1",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"undici": "^7.21.0",
"validator": "^13.15.26" "validator": "^13.15.26"
}, },
"devDependencies": { "devDependencies": {

View file

@ -1,43 +1,53 @@
import { ofetch } from "ofetch";
import { ProxyAgent } from "undici";
const wireguardDispatcher = new ProxyAgent("http://wireguard:8888");
const httpFetchClient = { const httpFetchClient = {
get: async (url: string, headers: Record<string, string>) => { get: async (url: string, headers: Record<string, string>) => {
const response = await fetch(url, { const response = await ofetch(url, {
method: "GET", method: "GET",
headers, headers,
dispatcher: wireguardDispatcher,
}); });
return response.json(); return response.json();
}, },
post: async (url: string, body: JSON, headers: Record<string, string>) => { post: async (url: string, body: JSON, headers: Record<string, string>) => {
const response = await fetch(url, { const response = await ofetch(url, {
method: "POST", method: "POST",
headers, headers,
body: JSON.stringify(body), body: JSON.stringify(body),
dispatcher: wireguardDispatcher,
}); });
return response.json(); return response.json();
}, },
put: async (url: string, body: JSON, headers: Record<string, string>) => { put: async (url: string, body: JSON, headers: Record<string, string>) => {
const response = await fetch(url, { const response = await ofetch(url, {
method: "PUT", method: "PUT",
headers, headers,
body: JSON.stringify(body), body: JSON.stringify(body),
dispatcher: wireguardDispatcher,
}); });
return response.json(); return response.json();
}, },
patch: async (url: string, body: JSON, headers: Record<string, string>) => { patch: async (url: string, body: JSON, headers: Record<string, string>) => {
const response = await fetch(url, { const response = await ofetch(url, {
method: "PATCH", method: "PATCH",
headers, headers,
body: JSON.stringify(body), body: JSON.stringify(body),
dispatcher: wireguardDispatcher,
}); });
return response.json(); return response.json();
}, },
delete: async (url: string, headers: Record<string, string>) => { delete: async (url: string, headers: Record<string, string>) => {
const response = await fetch(url, { const response = await ofetch(url, {
method: "DELETE", method: "DELETE",
headers, headers,
dispatcher: wireguardDispatcher,
}); });
return response.json(); return response.json();

View file

@ -4,13 +4,16 @@ export const prerender = false;
export const POST: APIRoute = async () => { export const POST: APIRoute = async () => {
try { try {
return new Response( return new Response(JSON.stringify(await cap.createChallenge()), {
JSON.stringify(await cap.createChallenge({ challengeDifficulty: 4 })),
{
status: 200, status: 200,
}, });
} catch (error) {
return new Response(
JSON.stringify({
success: false,
error: error instanceof Error ? error.message : String(error),
}),
{ status: 400 },
); );
} catch {
return new Response(JSON.stringify({ success: false }), { status: 400 });
} }
}; };