DEV Community

Paulo Fox
Paulo Fox

Posted on

Building a Website-as-a-Service: From Lead to Live HTTPS Site in Under 24 Hours

A dentist in Fortaleza asked me to build her a website. I quoted R$1.500 and six weeks. She hired someone on Fiverr for R$300 and got it in two days. She was right.

Traditional web agencies are pricing themselves out of the small business market in Brazil. I decided to automate the entire pipeline — from lead discovery to live website — and see how low I could push the cost. The result is Fox WaaS: a Website-as-a-Service that deploys a professional site in under 24 hours for R$299 setup + R$79/month.


The Stack

Google Maps Scraper
        │
        ▼
Lead Scorer (has website? quality score)
        │
        ▼
WhatsApp Outreach (via Evolution API)
        │
        ▼
Template Engine (AI-personalized content)
        │
        ▼
deploy_site.sh (Nginx + SSL + Cloudflare DNS)
        │
        ▼
Live HTTPS site in <24h
Enter fullscreen mode Exit fullscreen mode

Everything is automated except the client approval step (they review before go-live).


Lesson 1: Google Maps Is the Best Lead Source for Brazilian SMBs

We scrape Google Maps for businesses in a city + category (dentistas Fortaleza, restaurantes Maceió) using the Places API. The scoring model identifies the best leads:

def score_lead(business: dict) -> int:
    score = 0

    # High-value signals
    if business.get("rating") and business["rating"] >= 4.0:
        score += 25  # Reviews exist = real business
    if business.get("user_ratings_total", 0) >= 10:
        score += 20  # Established business

    # No website = our target customer
    if not business.get("website"):
        score += 30  # Primary signal: no digital presence
    elif "facebook.com" in business.get("website", ""):
        score += 20  # Facebook page only = weak web presence

    # Category multiplier (high-ticket services)
    high_value = ["dentista", "clínica", "advocacia", "restaurante"]
    if any(cat in business.get("types", []) for cat in high_value):
        score += 15

    return score  # 0–100, target: ≥ 60
Enter fullscreen mode Exit fullscreen mode

Leads scoring ≥60 get contacted. Leads scoring ≥80 get priority outreach.


Lesson 2: Template Engine With AI Personalization

We have 8 base templates (restaurant, clinic, law firm, beauty salon, gym, retail, services, generic). Each template is personalized with the client's actual business data.

async def generate_site_content(business: dict, template: str) -> dict:
    """Generate personalized copy for each HTML section."""

    sections = {}

    # Hero section
    sections["hero_title"] = await llm_complete(
        f"Write a compelling 6-word tagline for this business: {business['name']}. "
        f"Category: {business['category']}. City: {business['city']}. "
        f"Output ONLY the tagline, no quotes."
    )

    # About section
    sections["about_text"] = await llm_complete(
        f"Write 2 sentences about {business['name']} in Brazilian Portuguese. "
        f"Mention: city, years in business (if known), specialty. "
        f"Tone: professional, warm. Do not use 'somos' or 'nossa empresa'."
    )

    # Services
    sections["services"] = await llm_complete(
        f"List 6 services for a {business['category']} business in Brazil. "
        f"Format: JSON array of {{name, description(1 sentence), icon(emoji)}}. "
        f"JSON only, no markdown."
    )

    return sections
Enter fullscreen mode Exit fullscreen mode

The personalized content is injected into the template via Jinja2. Result: 2,400 template × content combinations, each genuinely different.


Lesson 3: One-Command Deploy (Nginx + SSL + DNS)

The deploy_site.sh script does the full deployment in one command:

#!/bin/bash
# Usage: ./deploy_site.sh <slug> <domain> <site_dir>
SLUG=$1   # e.g. "clinica-maria-jose"
DOMAIN=$2 # e.g. "clinicamariajose.com.br"
SITE_DIR=$3

# 1. Copy files to nginx root
sudo mkdir -p /var/www/waas/$SLUG
sudo cp -r $SITE_DIR/* /var/www/waas/$SLUG/

# 2. Generate nginx config from template
envsubst '$SLUG $DOMAIN' < /etc/nginx/templates/waas.conf.tmpl \
  | sudo tee /etc/nginx/sites-available/$SLUG > /dev/null
sudo ln -sf /etc/nginx/sites-available/$SLUG /etc/nginx/sites-enabled/

# 3. Test config before reload
sudo nginx -t && sudo nginx -s reload

# 4. Issue SSL certificate (Certbot + Cloudflare DNS challenge)
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d $DOMAIN -d www.$DOMAIN \
  --non-interactive --agree-tos --email admin@centralfox.online

# 5. Set up Cloudflare DNS (A record pointing to VPS)
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
  -H "X-Auth-Email: $CF_EMAIL" \
  -H "X-Auth-Key: $CF_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"type\":\"A\",\"name\":\"$DOMAIN\",\"content\":\"$VPS_IP\",\"proxied\":true}"

echo "✅ $DOMAIN deployed at https://$DOMAIN"
Enter fullscreen mode Exit fullscreen mode

Total time from command to live HTTPS site: 47 seconds.


Lesson 4: WhatsApp Outreach With Evolution API

Cold email in Brazil has near-zero open rates. WhatsApp has 95% open rates and most business owners respond within 2 hours.

async def send_outreach(phone: str, business_name: str, preview_url: str) -> bool:
    """Send personalized WhatsApp message with site preview."""

    message = (
        f"Olá! Vi que a *{business_name}* ainda não tem site profissional. "
        f"Montei uma prévia gratuita para vocês: {preview_url}\n\n"
        f"Site pronto em 24h por R$299. Posso mostrar mais detalhes?"
    )

    resp = await httpx.post(
        f"{EVOLUTION_API_URL}/message/sendText/{INSTANCE_NAME}",
        headers={"apikey": EVOLUTION_API_KEY},
        json={"number": f"55{phone}@s.whatsapp.net", "text": message}
    )
    return resp.status_code == 201
Enter fullscreen mode Exit fullscreen mode

The preview URL is the key. We deploy a "preview" version of the personalized site before contacting the lead. They click a link and see their own business already built. Conversion rate: 18% (vs 3% for text-only outreach).


Lesson 5: The Economics

Cost Amount
VPS (Contabo 24GB) R$82/month
Cloudflare (free tier) R$0
Certbot SSL R$0
Claude API (content gen) ~R$0.12/site
WhatsApp (Evolution API) R$0 (self-hosted)
Total per site ~R$0.50

At R$299 setup + R$79/month, the margin on a 100-site portfolio:

  • Monthly recurring: 100 × R$79 = R$7.900
  • Infrastructure: R$82 + ~R$200 (misc) = R$282
  • Net margin: ~96%

The bottleneck is not infrastructure — it's sales. Each site takes ~45 minutes of human time (content review, client approval, small edits).


Results After 2 Months

  • 87 sites deployed (73 client-paid, 14 preview/demo)
  • Average deploy time: 19 hours from payment to go-live
  • Lighthouse scores: 91–97 across all sites
  • Client churn: 3/73 (4%) — all price-objections in month 2

What's Next

Fox WaaS is live at sites.centralfox.online.

Roadmap:

  • E-commerce integration (MercadoPago + simple product catalog)
  • WhatsApp ordering system (customers order directly via WA button)
  • Dashboard for clients (update photos, hours, contact info without contacting us)
  • Multi-city expansion beyond Fortaleza

If you're building automated deployment pipelines, WaaS businesses, or have questions about nginx automation, Cloudflare API, or the Brazilian SMB market — drop a comment.

Built with: Python 3.12 · FastAPI · Nginx · Certbot · Cloudflare API · Evolution API · Claude Code (Anthropic)

🔗 sites.centralfox.online | Reddit u/foxdigitaldev

Top comments (0)