Skip to content
This repository has been archived by the owner on Dec 18, 2024. It is now read-only.

Commit

Permalink
Update to 0.2.0; FRP integration
Browse files Browse the repository at this point in the history
  • Loading branch information
davidcaseria committed Nov 18, 2024
1 parent 76c2c0f commit e67b5e2
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 117 deletions.
14 changes: 9 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
FROM rust:1.79-slim-bookworm AS rust-builder
FROM rust:1.82-slim-bookworm AS rust-builder

RUN apt-get update -qqy && \
apt-get upgrade -qqy && \
DEBIAN_FRONTEND=noninteractive apt-get install -qqy --no-install-recommends \
protobuf-compiler && \
ca-certificates libssl-dev pkg-config protobuf-compiler && \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*

WORKDIR /build
COPY ./chamberlain .
RUN rustup toolchain install stable
COPY ./chamberlain .
RUN cargo +stable install --locked --path .

FROM golang:1.23-bookworm AS go-builder
Expand All @@ -28,6 +28,7 @@ RUN apt-get update -qqy && \
jq \
netcat-openbsd \
nginx \
openssl \
python3-certbot-nginx \
tzdata \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/* /etc/nginx/sites-enabled/* /etc/nginx/sites-available/*
Expand All @@ -38,13 +39,16 @@ RUN curl -sLo /usr/local/bin/yq https://github.com/mikefarah/yq/releases/downloa

COPY --from=rust-builder /usr/local/cargo/bin/chamberlain /bin/chamberlain
COPY --from=rust-builder /usr/local/cargo/bin/chamberlaind /bin/chamberlaind
COPY --from=go-builder /build/nws /bin/nws
COPY --from=go-builder /build/bin/frpc /bin/frpc

ADD ./docker_entrypoint.sh /usr/local/bin/docker_entrypoint.sh
RUN chmod a+x /usr/local/bin/docker_entrypoint.sh
ADD ./health_check.sh /usr/local/bin/health_check.sh
RUN chmod a+x /usr/local/bin/health_check.sh
COPY nginx.conf /etc/nginx/nginx.conf
COPY conf/frpc.toml.template /etc/frp/frpc.toml.template
COPY conf/letsencrypt.ini /etc/letsencrypt/cli.ini
COPY conf/nginx.conf.template /etc/nginx/nginx.conf.template
COPY conf/nginx_initial.conf.template /etc/nginx/nginx_initial.conf.template
RUN mkdir -p /var/www/certbot

WORKDIR /root/data
Expand Down
2 changes: 1 addition & 1 deletion chamberlain
30 changes: 30 additions & 0 deletions conf/frpc.toml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
serverAddr = "clan.svrgn.app"
serverPort = 7000

[[proxies]]
name = "mint-http"
type = "http"
localPort = 8080
httpUser = "$FRP_USER"
httpPassword = "$FRP_PASSWORD"
customDomains = ["$CLAN_NAME.clan.svrgn.app"]

[[proxies]]
name = "mint-https"
type = "https"
localPort = 8443
customDomains = ["$CLAN_NAME.clan.svrgn.app"]

[[proxies]]
name = "mgmt-http"
type = "http"
localPort = 8080
httpUser = "$FRP_USER"
httpPassword = "$FRP_PASSWORD"
customDomains = ["$CLAN_NAME.clanmgmt.svrgn.app"]

[[proxies]]
name = "mgmt-https"
type = "https"
localPort = 8443
customDomains = ["$CLAN_NAME.clanmgmt.svrgn.app"]
3 changes: 3 additions & 0 deletions conf/letsencrypt.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
config-dir = /root/data/letsencrypt
logs-dir = /root/data/letsencrypt/logs
work-dir = /root/data/letsencrypt/work
71 changes: 71 additions & 0 deletions conf/nginx.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
events {
worker_connections 1024; # Example setting
}

http {
# HTTP-to-HTTPS Redirection Server
server {
listen 8080;
server_name $CLAN_NAME.clan.svrgn.app $CLAN_NAME.clanmgmt.svrgn.app;

# Redirect all HTTP requests to HTTPS
location / {
return 301 https://$host$request_uri;
}

# Serve Certbot's ACME challenge for certificate renewal
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}

# HTTPS Server for HTTP Service
server {
listen 8443 ssl http2;
server_name $CLAN_NAME.clan.svrgn.app;

# SSL certificate paths
ssl_certificate /root/data/letsencrypt/live/$CLAN_NAME.clan.svrgn.app/fullchain.pem;
ssl_certificate_key /root/data/letsencrypt/live/$CLAN_NAME.clan.svrgn.app/privkey.pem;

# Proxy HTTP requests to the local HTTP server on port 3338
location / {
proxy_pass http://localhost:3338;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

# HTTPS Server for gRPC Service
server {
listen 8443 ssl http2;
server_name $CLAN_NAME.clanmgmt.svrgn.app;

# SSL certificate paths
ssl_certificate /root/data/letsencrypt/live/$CLAN_NAME.clanmgmt.svrgn.app/fullchain.pem;
ssl_certificate_key /root/data/letsencrypt/live/$CLAN_NAME.clanmgmt.svrgn.app/privkey.pem;

# Enable gRPC proxying
location / {
grpc_pass grpc://localhost:3339;
error_page 502 = /error502grpc;

# gRPC-specific headers
grpc_set_header Host $host;
grpc_set_header X-Real-IP $remote_addr;
grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
grpc_set_header X-Forwarded-Proto $scheme;
}

# Custom 502 page to handle gRPC errors
location = /error502grpc {
internal;
default_type application/grpc;
add_header grpc-status 14;
add_header content-length 0;
return 204;
}
}
}
15 changes: 15 additions & 0 deletions conf/nginx_initial.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
events {
worker_connections 1024; # Example setting
}

http {
server {
listen 8080;
server_name $CLAN_NAME.clan.svrgn.app $CLAN_NAME.clanmgmt.svrgn.app;

# Serve Certbot's ACME challenge for certificate renewal
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
}
173 changes: 123 additions & 50 deletions docker_entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,86 +3,159 @@
set -e

CONFIG_FILE="/root/data/start9/config.yaml"
STATS_FILE="/root/data/start9/stats.yaml"
echo "Starting Chamberlain from config file: $CONFIG_FILE"

BITCOIND_RPC_USER=$(yq '.bitcoind-rpc-user' "$CONFIG_FILE")
BITCOIND_RPC_PASSWORD=$(yq '.bitcoind-rpc-password' "$CONFIG_FILE")
NWS_ENABLED=$(yq '.nws.enabled' "$CONFIG_FILE")
TOR_ADDRESS=$(yq '.tor-address' "$CONFIG_FILE")
export BITCOIND_RPC_USER=$(yq '.bitcoind-rpc-user' "$CONFIG_FILE")
export BITCOIND_RPC_PASSWORD=$(yq '.bitcoind-rpc-password' "$CONFIG_FILE")

echo "NWS enabled: $NWS_ENABLED"
if [ "$NWS_ENABLED" = "true" ]; then
export NOSTR_RELAYS="$(yq '.nws.relay' "$CONFIG_FILE")"
NOSTR_PRIVATE_KEY="$(yq '.nws.private-key' "$CONFIG_FILE")"
if [ -z "$NOSTR_PRIVATE_KEY" ] || [ "$NOSTR_PRIVATE_KEY" = "null" ]; then
echo "Generating new NOSTR private key"
NOSTR_PRIVATE_KEY=$(openssl rand -hex 32)
yq -i ".nws.private-key = \"$NOSTR_PRIVATE_KEY\"" "$CONFIG_FILE"
fi
export NOSTR_PRIVATE_KEY
export PUBLIC="false"
export BACKEND_HOST="localhost:3338"
fi

MINT_URL=$(yq '.mint-url' "$CONFIG_FILE")
export MINT_URL=$(yq '.mint.url' "$CONFIG_FILE")
if [ -z "$MINT_URL" ] || [ "$MINT_URL" = "null" ]; then
MINT_URL="http://$TOR_ADDRESS"
export MINT_URL="http://$TOR_ADDRESS"
fi
MINT_NAME=$(yq '.mint-name' "$CONFIG_FILE")
export MINT_NAME=$(yq '.mint.name' "$CONFIG_FILE")
if [ -z "$MINT_NAME" ] || [ "$MINT_NAME" = "null" ]; then
MINT_NAME="Chamberlain"
export MINT_NAME="Chamberlain"
fi
MINT_DESCRIPTION=$(yq '.mint-description' "$CONFIG_FILE")
export MINT_DESCRIPTION=$(yq '.mint.description' "$CONFIG_FILE")
if [ -z "$MINT_DESCRIPTION" ] || [ "$MINT_DESCRIPTION" = "null" ]; then
MINT_DESCRIPTION="A chamberlain powered cashu mint."
export MINT_DESCRIPTION="A chamberlain powered cashu mint."
fi
MINT_CONTACT_EMAIL=$(yq '.contact-info.email' "$CONFIG_FILE")
export MINT_MOTD=$(yq '.mint.motd' "$CONFIG_FILE")
if [ -z "$MINT_MOTD" ] || [ "$MINT_MOTD" = "null" ]; then
export MINT_MOTD=""
fi
export MINT_CONTACT_EMAIL=$(yq '.mint.contact-info.email' "$CONFIG_FILE")
if [ -z "$MINT_CONTACT_EMAIL" ] || [ "$MINT_CONTACT_EMAIL" = "null" ]; then
MINT_CONTACT_EMAIL=""
export MINT_CONTACT_EMAIL=""
fi
MINT_CONTACT_TWITTER=$(yq '.contact-info.twitter' "$CONFIG_FILE")
export MINT_CONTACT_TWITTER=$(yq '.mint.contact-info.twitter' "$CONFIG_FILE")
if [ -z "$MINT_CONTACT_TWITTER" ] || [ "$MINT_CONTACT_TWITTER" = "null" ]; then
MINT_CONTACT_TWITTER=""
export MINT_CONTACT_TWITTER=""
fi
MINT_CONTACT_NPUB=$(yq '.contact-info.npub' "$CONFIG_FILE")
export MINT_CONTACT_NPUB=$(yq '.mint.contact-info.npub' "$CONFIG_FILE")
if [ -z "$MINT_CONTACT_NPUB" ] || [ "$MINT_CONTACT_NUB" = "null" ]; then
MINT_CONTACT_NPUB=""
export MINT_CONTACT_NPUB=""
fi
PASSWORD=$(tr -dc a-km-zA-HJ-NP-Z2-9 </dev/urandom | head -c 8)

echo "Writing password to /root/data/start9/stats.yaml"
cat << EOF > /root/data/start9/stats.yaml
---
version: 2
data:
Password:
type: string
value: "$PASSWORD"
description: Auth token password.
copyable: true
qr: false
masked: true
EOF
if [ ! -f "/root/data/auth_token" ]; then
echo "Writing default auth token to /root/data/auth_token"
dd if=/dev/zero of=/root/data/auth_token bs=32 count=1
fi

nws exit --port 4443 --target http://localhost:3338 &
chamberlaind \
--data-dir /root/data \
--mint-url "$MINT_URL" \
--mint-name "$MINT_NAME" \
--mint-description "$MINT_DESCRIPTION" \
--mint-motd "$MINT_MOTD" \
--mint-contact-email "$MINT_CONTACT_EMAIL" \
--mint-contact-twitter "$MINT_CONTACT_TWITTER" \
--mint-contact-npub "$MINT_CONTACT_NPUB" \
--password "$PASSWORD" \
--bitcoind-rpc-url "http://bitcoind.embassy:8332" \
--bitcoind-rpc-user "$BITCOIND_RPC_USER" \
--bitcoind-rpc-password "$BITCOIND_RPC_PASSWORD" \
--lightning-auto-announce=false \
--rpc-auth-jwks-url "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_XaIPDAMB1/.well-known/jwks.json" \
--log-level debug &

cat << EOF > "$STATS_FILE"
---
version: 2
data:
"Mint URL":
type: string
value: "$MINT_URL"
description: "The URL of the mint."
copyable: true
qr: false
masked: false
EOF

SOVEREIGN_APP_ENABLED=$(yq '.sovereign-app.enabled' "$CONFIG_FILE")
echo "sovereign.app integration enabled: $SOVEREIGN_APP_ENABLED"
if [ "$SOVEREIGN_APP_ENABLED" = "true" ]; then
# Set up sovereign.app integration
URL="https://api.sovereign.app/clan/link"
LINK_DETAILS_PATH="/root/data/clan_link.json"

if [ -f "$LINK_DETAILS_PATH" ]; then
echo "Clan link already established."
else
echo "Requesting link details..."
response=$(curl -s -X POST "$URL")
export CODE=$(echo "$response" | jq -r '.code')
if [ -n "$CODE" ]; then
echo "Link code retrieved: $CODE"
yq -i '.["Link Code"] = env(CODE)' "$STATS_FILE"
else
echo "Failed to retrieve link code."
exit 1
fi
while true; do
rm -f "$LINK_DETAILS_PATH"
response=$(curl -s -w "%{http_code}" -o "$LINK_DETAILS_PATH" "$URL/$CODE")
status_code="${response: -3}"
if [ "$status_code" -eq 200 ]; then
echo "Link details saved to $LINK_DETAILS_PATH (restarting)"
exit 0
else
echo "Link not setup (status: $status_code)"
sleep 5 # Wait for 5 seconds before retrying
fi
done
fi

export CLAN_NAME=$(jq -r '.clan_name' "$LINK_DETAILS_PATH")
export MINT_URL="https://$CLAN_NAME.clan.svrgn.app"
yq -i '.mint.url = env(MINT_URL)' "$CONFIG_FILE"

# Start FRPC
export FRP_USER=$(jq -r '.sub' "$LINK_DETAILS_PATH")
export FRP_PASSWORD=$(jq -r '.token' "$LINK_DETAILS_PATH")
if [ -z "$FRP_USER" ] || [ -z "$FRP_PASSWORD" ]; then
echo "Failed to retrieve FRP credentials."
exit 1
fi
echo "Starting frpc..."
envsubst '${CLAN_NAME} ${FRP_USER} ${FRP_PASSWORD}' < /etc/frp/frpc.toml.template > /etc/frp/frpc.toml
frpc -c /etc/frp/frpc.toml &

# Obtain or renew SSL certificates
if [ ! -d "/root/data/letsencrypt/live/$CLAN_NAME.clan.svrgn.app" ]; then
echo "Starting nginx..."
envsubst '${CLAN_NAME}' < /etc/nginx/nginx_initial.conf.template > /etc/nginx/nginx.conf
nginx -g "daemon off;" &
NGINX_PID=$!
echo "Obtaining new SSL certificate for $CLAN_NAME.clan.svrgn.app..."
certbot certonly --nginx --non-interactive --agree-tos --email "$MINT_CONTACT_EMAIL" -d "$CLAN_NAME.clan.svrgn.app"
kill $NGINX_PID
else
echo "Checking renewal status for $CLAN_NAME.clan.svrgn.app..."
# certbot renew --cert-name "$CLAN_NAME.clan.svrgn.app" --dry-run && echo "Certificate is up to date." || {
# echo "Renewing SSL certificate for $CLAN_NAME.clan.svrgn.app..."
# certbot renew --nginx --non-interactive --agree-tos
# }
fi

if [ ! -d "/root/data/letsencrypt/live/$CLAN_NAME.clanmgmt.svrgn.app" ]; then
echo "Starting nginx..."
envsubst '${CLAN_NAME}' < /etc/nginx/nginx_initial.conf.template > /etc/nginx/nginx.conf
nginx -g "daemon off;" &
NGINX_PID=$!
echo "Obtaining new SSL certificate for $CLAN_NAME.clanmgmt.svrgn.app..."
certbot certonly --nginx --non-interactive --agree-tos --email "$MINT_CONTACT_EMAIL" -d "$CLAN_NAME.clanmgmt.svrgn.app"
kill $NGINX_PID
else
echo "Checking renewal status for $CLAN_NAME.clanmgmt.svrgn.app..."
# certbot renew --cert-name "$CLAN_NAME.clanmgmt.svrgn.app" --dry-run && echo "Certificate is up to date." || {
# echo "Renewing SSL certificate for $CLAN_NAME.clanmgmt.svrgn.app..."
# certbot renew --nginx --non-interactive --agree-tos
# }
fi

# Switch to full SSL NGINX configuration
echo "Starting nginx with SSL configuration..."
envsubst '${CLAN_NAME}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf
nginx -g "daemon off;" &
fi

echo "Chamberlain started successfully."
wait -n
exit $?
2 changes: 1 addition & 1 deletion manifest.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
id: chamberlain
title: "Chamberlain"
version: 0.1.2
version: 0.2.0
release-notes: |
Initial release of Chamberlain from sovereign.app.
license: MIT+CC
Expand Down
Loading

0 comments on commit e67b5e2

Please sign in to comment.