replace NPM with vanilla nginx + certbot
- nginx:alpine replaces nginx-proxy-manager - certbot on host with standalone issuance and auto-renewal - per-site nginx configs in conf.d/ (HTTP->HTTPS, bare->www) - container names use underscores (timothykim_net) - setup.sh: automated cert issuance, dynamic app startup - deploy.sh: nginx -t guard, graceful image-not-found - new-app.sh: Gitea API repo creation, nginx conf generation - add ARCHITECTURE.md, USECASES.md, CLAUDE.md - remove old NPM data/certs from tracking
This commit is contained in:
+14
-1
@@ -12,5 +12,18 @@ APP="${CMD#deploy-}"
|
||||
cd /opt/hantim
|
||||
git pull
|
||||
cd "docker/$APP"
|
||||
docker compose pull
|
||||
if ! docker compose pull; then
|
||||
echo "Image not yet available for $APP — skipping. It will deploy when the app repo is first pushed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$APP" = "nginx" ]; then
|
||||
# Test config before applying — a bad config (e.g. missing cert) would take down all sites
|
||||
docker compose run --rm -T nginx nginx -t
|
||||
fi
|
||||
|
||||
docker compose up -d
|
||||
|
||||
if [ "$APP" = "nginx" ]; then
|
||||
docker exec nginx nginx -s reload
|
||||
fi
|
||||
|
||||
+123
-5
@@ -1,13 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_URL="https://git.timothykim.net"
|
||||
GITEA_ORG="hantim"
|
||||
TEMPLATE_REPO="static-site-template"
|
||||
|
||||
if [ -z "${1:-}" ]; then
|
||||
echo "Usage: ./scripts/new-app.sh <app-name>"
|
||||
echo "Example: ./scripts/new-app.sh my-blog"
|
||||
echo "Usage: ./scripts/new-app.sh <domain>"
|
||||
echo "Example: ./scripts/new-app.sh hcsuzuki.net"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
APP="$1"
|
||||
CONTAINER_NAME="${APP//./_}"
|
||||
|
||||
if ! [[ "$APP" =~ ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ ]]; then
|
||||
echo "Error: app name must be alphanumeric (hyphens, dots, underscores allowed)."
|
||||
@@ -21,6 +26,60 @@ if [ -d "$REPO_ROOT/docker/$APP" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Check dependencies ---
|
||||
|
||||
if ! command -v bw &>/dev/null; then
|
||||
echo "Error: Bitwarden CLI (bw) is not installed."
|
||||
echo " npm install -g @bitwarden/cli"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq &>/dev/null; then
|
||||
echo "Error: jq is not installed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Get Gitea API token from Bitwarden ---
|
||||
|
||||
if bw status 2>/dev/null | grep -q '"status":"unauthenticated"'; then
|
||||
echo "Log in to Bitwarden:"
|
||||
bw login
|
||||
fi
|
||||
|
||||
if bw status 2>/dev/null | grep -q '"status":"locked"'; then
|
||||
BW_SESSION=$(bw unlock --raw)
|
||||
export BW_SESSION
|
||||
fi
|
||||
|
||||
bw sync --session "${BW_SESSION:-}"
|
||||
GITEA_TOKEN=$(bw get notes hantim-new-app-script --session "${BW_SESSION:-}")
|
||||
|
||||
# --- Create Gitea repo from template ---
|
||||
|
||||
echo "Creating Gitea repo $GITEA_ORG/$APP from template $TEMPLATE_REPO..."
|
||||
HTTP_CODE=$(curl -s -o /tmp/new-app-response.json -w "%{http_code}" \
|
||||
-X POST "$GITEA_URL/api/v1/repos/$GITEA_ORG/$TEMPLATE_REPO/generate" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"owner\": \"$GITEA_ORG\",
|
||||
\"name\": \"$APP\",
|
||||
\"git_content\": true,
|
||||
\"labels\": false,
|
||||
\"webhooks\": false
|
||||
}")
|
||||
|
||||
if [ "$HTTP_CODE" != "201" ]; then
|
||||
echo "Error: Failed to create repo (HTTP $HTTP_CODE)"
|
||||
cat /tmp/new-app-response.json
|
||||
rm -f /tmp/new-app-response.json
|
||||
exit 1
|
||||
fi
|
||||
rm -f /tmp/new-app-response.json
|
||||
echo " Created: $GITEA_URL/$GITEA_ORG/$APP"
|
||||
|
||||
# --- Create local files in hantim-server ---
|
||||
|
||||
echo "Creating docker/$APP/compose.yml..."
|
||||
mkdir -p "$REPO_ROOT/docker/$APP"
|
||||
cat > "$REPO_ROOT/docker/$APP/compose.yml" <<EOF
|
||||
@@ -28,6 +87,7 @@ services:
|
||||
app:
|
||||
image: git.timothykim.net/hantim/$APP:latest
|
||||
restart: unless-stopped
|
||||
container_name: $CONTAINER_NAME
|
||||
networks:
|
||||
- shared
|
||||
|
||||
@@ -60,12 +120,70 @@ jobs:
|
||||
OUTER
|
||||
sed -i "s/APP_PLACEHOLDER/$APP/g" "$REPO_ROOT/.gitea/workflows/deploy-$APP.yml"
|
||||
|
||||
echo "Creating docker/nginx/conf.d/$APP.conf..."
|
||||
cat > "$REPO_ROOT/docker/nginx/conf.d/$APP.conf" <<NGINX
|
||||
# Redirect HTTP to HTTPS, bare domain to www
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name $APP www.$APP;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://www.$APP\$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# Redirect bare HTTPS domain to www
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
server_name $APP;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/$APP/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/$APP/privkey.pem;
|
||||
|
||||
return 301 https://www.$APP\$request_uri;
|
||||
}
|
||||
|
||||
# Main site
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
server_name www.$APP;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/$APP/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/$APP/privkey.pem;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=63072000; preload" always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://$CONTAINER_NAME:80;
|
||||
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;
|
||||
}
|
||||
}
|
||||
NGINX
|
||||
|
||||
echo ""
|
||||
echo "Done! Files created:"
|
||||
echo " - Gitea repo: $GITEA_URL/$GITEA_ORG/$APP"
|
||||
echo " - docker/$APP/compose.yml"
|
||||
echo " - .gitea/workflows/deploy-$APP.yml"
|
||||
echo " - docker/nginx/conf.d/$APP.conf"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit docker/$APP/compose.yml to fit your app"
|
||||
echo " 2. Commit and push to deploy"
|
||||
echo " 3. Configure the proxy host in Nginx Proxy Manager"
|
||||
echo " 1. Issue SSL cert on the server (BEFORE pushing nginx config):"
|
||||
echo " docker stop nginx"
|
||||
echo " certbot certonly --standalone --non-interactive --agree-tos --register-unsafely-without-email --cert-name $APP -d $APP -d www.$APP"
|
||||
echo " docker start nginx"
|
||||
echo " 2. Commit and push hantim-server to deploy"
|
||||
echo " 3. Clone $GITEA_URL/$GITEA_ORG/$APP and customize it"
|
||||
echo " 4. Edit docker/$APP/compose.yml if needed"
|
||||
|
||||
Reference in New Issue
Block a user