Add marketing site for makeyourown.website
Static single-page marketing site with dark theme, 3-tier pricing, LLM/agent SEO (llms.txt), and deployment setup that overlays onto the existing WebsiteBox nginx via docker-compose.override.yml without modifying any core project files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
113
website/deploy/deploy.sh
Executable file
113
website/deploy/deploy.sh
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
# Deploy the WebsiteBox marketing site alongside an existing WebsiteBox installation.
|
||||
#
|
||||
# This script:
|
||||
# 1. Generates the active nginx config (HTTP-only initially)
|
||||
# 2. Copies the docker-compose override to the project root
|
||||
# 3. Restarts nginx to pick up the new config
|
||||
# 4. Acquires an SSL certificate via the existing certbot container
|
||||
# 5. Swaps to the HTTPS nginx config and reloads
|
||||
#
|
||||
# Prerequisites:
|
||||
# - WebsiteBox is already running (docker compose up -d)
|
||||
# - DNS A record for the marketing domain points to this server
|
||||
# - Run from the WebsiteBox project root: ./website/deploy/deploy.sh
|
||||
#
|
||||
# This does NOT modify any core WebsiteBox files.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
MARKETING_DOMAIN="makeyourown.website"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
echo "========================================"
|
||||
echo " WebsiteBox Marketing Site Deploy"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Domain: ${MARKETING_DOMAIN}"
|
||||
echo "Project: ${PROJECT_ROOT}"
|
||||
echo ""
|
||||
|
||||
# Check we're in the right place
|
||||
if [ ! -f "${PROJECT_ROOT}/docker-compose.yml" ]; then
|
||||
echo "ERROR: docker-compose.yml not found in ${PROJECT_ROOT}"
|
||||
echo "Run this script from the WebsiteBox project root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check WebsiteBox is running
|
||||
if ! docker compose -f "${PROJECT_ROOT}/docker-compose.yml" ps --status running | grep -q nginx; then
|
||||
echo "ERROR: WebsiteBox nginx is not running."
|
||||
echo "Start it first: docker compose up -d"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read ADMIN_EMAIL from .env for certbot
|
||||
ADMIN_EMAIL=""
|
||||
if [ -f "${PROJECT_ROOT}/.env" ]; then
|
||||
ADMIN_EMAIL=$(grep '^ADMIN_EMAIL=' "${PROJECT_ROOT}/.env" | cut -d'=' -f2)
|
||||
fi
|
||||
if [ -z "$ADMIN_EMAIL" ]; then
|
||||
echo "ERROR: ADMIN_EMAIL not found in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 1: Generate HTTP-only nginx config (for ACME challenge)
|
||||
echo "[1/5] Generating HTTP nginx config..."
|
||||
sed "s/MARKETING_DOMAIN_PLACEHOLDER/${MARKETING_DOMAIN}/g" \
|
||||
"${SCRIPT_DIR}/marketing.conf" > "${SCRIPT_DIR}/active-marketing.conf"
|
||||
|
||||
# Step 2: Copy docker-compose override to project root
|
||||
echo "[2/5] Installing docker-compose override..."
|
||||
cp "${SCRIPT_DIR}/docker-compose.override.yml" "${PROJECT_ROOT}/docker-compose.override.yml"
|
||||
|
||||
# Step 3: Restart nginx to pick up the new config + volume mount
|
||||
echo "[3/5] Restarting nginx with marketing site..."
|
||||
cd "${PROJECT_ROOT}"
|
||||
docker compose up -d nginx
|
||||
sleep 3
|
||||
|
||||
# Verify nginx is serving the marketing domain
|
||||
echo " Verifying HTTP response..."
|
||||
if ! docker compose exec nginx curl -sf -H "Host: ${MARKETING_DOMAIN}" http://localhost/ > /dev/null 2>&1; then
|
||||
echo "WARNING: nginx did not respond for ${MARKETING_DOMAIN}. Check the config."
|
||||
echo "Continuing anyway — SSL acquisition may still work if DNS is correct."
|
||||
fi
|
||||
|
||||
# Step 4: Acquire SSL certificate
|
||||
echo "[4/5] Acquiring SSL certificate for ${MARKETING_DOMAIN}..."
|
||||
if docker compose exec certbot certbot certonly \
|
||||
--webroot \
|
||||
-w /var/www/certbot \
|
||||
-d "${MARKETING_DOMAIN}" \
|
||||
--agree-tos \
|
||||
--email "${ADMIN_EMAIL}" \
|
||||
--non-interactive \
|
||||
--no-eff-email; then
|
||||
|
||||
echo " SSL certificate acquired!"
|
||||
|
||||
# Step 5: Swap to HTTPS config and reload
|
||||
echo "[5/5] Activating HTTPS config..."
|
||||
sed "s/MARKETING_DOMAIN_PLACEHOLDER/${MARKETING_DOMAIN}/g" \
|
||||
"${SCRIPT_DIR}/marketing-ssl.conf" > "${SCRIPT_DIR}/active-marketing.conf"
|
||||
|
||||
docker compose exec nginx nginx -s reload
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Marketing site is live!"
|
||||
echo " https://${MARKETING_DOMAIN}"
|
||||
echo "========================================"
|
||||
else
|
||||
echo ""
|
||||
echo "WARNING: SSL certificate acquisition failed."
|
||||
echo "The marketing site is running on HTTP at http://${MARKETING_DOMAIN}"
|
||||
echo ""
|
||||
echo "Common causes:"
|
||||
echo " - DNS A record for ${MARKETING_DOMAIN} does not point to this server"
|
||||
echo " - DNS hasn't propagated yet (wait a few minutes and re-run)"
|
||||
echo ""
|
||||
echo "To retry SSL only, re-run this script."
|
||||
fi
|
||||
45
website/deploy/marketing-ssl.conf
Normal file
45
website/deploy/marketing-ssl.conf
Normal file
@@ -0,0 +1,45 @@
|
||||
# Marketing site — HTTPS server block
|
||||
# Activated after SSL certificate is acquired
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name MARKETING_DOMAIN_PLACEHOLDER;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/MARKETING_DOMAIN_PLACEHOLDER/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/MARKETING_DOMAIN_PLACEHOLDER/privkey.pem;
|
||||
include /etc/nginx/snippets/ssl-params.conf;
|
||||
|
||||
root /var/www/marketing;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Static file caching
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff|woff2|ttf|eot|xml|txt)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-Frame-Options SAMEORIGIN always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTP to HTTPS redirect
|
||||
server {
|
||||
listen 80;
|
||||
server_name MARKETING_DOMAIN_PLACEHOLDER;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
18
website/deploy/marketing.conf
Normal file
18
website/deploy/marketing.conf
Normal file
@@ -0,0 +1,18 @@
|
||||
# Marketing site — HTTP server block (pre-SSL)
|
||||
# Serves static files and handles ACME challenges for certificate acquisition
|
||||
# Replaced by marketing-ssl.conf once SSL is acquired
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name MARKETING_DOMAIN_PLACEHOLDER;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /var/www/marketing;
|
||||
index index.html;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user