Private
Public Access
1
0

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:
constantprojects
2026-02-24 11:58:48 -07:00
parent 2e06db3291
commit 53ac8f85ac
14 changed files with 2196 additions and 0 deletions

113
website/deploy/deploy.sh Executable file
View 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

View 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;
}
}

View 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;
}
}