Deploy a self-hosted WooCommerce stack with one command, full privacy control, and ARM64 support from Raspberry Pi 5 to DGX Spark.

Sovereign AI Webshop


Spin Up the Stack in One Shot

git clone https://github.com/sethuiyer/Document-Clusterer.git
cd sovereign-webshop
cp .env.example .env
docker compose up -d --build

WordPress installs automatically via WP-CLI on first start. You’ll see the login screen at http://localhost:8000 within two minutes. No browser tab juggling, no waiting for a cloud provider to provision a VM. The stack boots cleanly on both x86_64 and ARM64; I’ve tested it on a Raspberry Pi 5 (Ubuntu 24.04) and an NVIDIA DGX Spark (Ubuntu 22.04) without any changes.


What’s Inside the Docker Compose File

services:
  wordpress:
    build:
      context: .
      dockerfile: Dockerfile
      platforms:
        - linux/arm64
    ports:
      - "8000:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
      WP_ADMIN_USER: admin
      WP_ADMIN_PASSWORD: admin123
      WP_ADMIN_EMAIL: admin@localhost
    volumes:
      - ./wordpress/wp-content:/var/www/html/wp-content
    depends_on:
      - db
      - redis

  db:
    image: mariadb:11.4.2
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      timeout: 3s
      retries: 5

  redis:
    image: redis:7.2-alpine3.20
    command: redis-server --requirepass redispass
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "redispass", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  n8n:
    image: n8nio/n8n:1.52.1
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=n8nadmin
    volumes:
      - n8n_data:/home/node/.n8n

  api-bridge:
    build:
      context: ./services/api-bridge
      dockerfile: Dockerfile
    ports:
      - "8001:8001"
    environment:
      - MATRIX_HOMESERVER=https://matrix.example.com
      - MATRIX_ROOM_ID=!room:example.com
      - MATRIX_TOKEN=yourtoken
    volumes:
      - ./services/api-bridge:/app
      - /data/projects/shared:/shared:ro

This is the minimal set you need: WordPress 6.4.3, MariaDB 11.4.2, Redis 7.2, n8n 1.52.1 for workflows, and a Python API bridge for privacy-first integrations. All images are pinned to exact versions to avoid surprise upgrades that break ARM64 builds.


Custom WordPress Image with All the Right PHP Extensions

FROM wordpress:6.4.3-apache

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
    libzip-dev \
    libxml2-dev \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libwebp-dev && \
    docker-php-ext-install \
        bcmath \
        exif \
        gd \
        intl \
        mbstring \
        mysqli \
        opcache \
        pdo_mysql \
        soap \
        zip

# Install WP-CLI v2.10.0
RUN curl -fsSL https://github.com/wp-cli/wp-cli/releases/download/v2.10.0/wp-cli-2.10.0.phar -o /usr/local/bin/wp && \
    chmod +x /usr/local/bin/wp && \
    wp --version

# PHP limits for WooCommerce
RUN sed -i 's/memory_limit = .*/memory_limit = 512M/' /usr/local/etc/php/conf.d/docker-php-memory.ini && \
    sed -i 's/upload_max_filesize = .*/upload_max_filesize = 64M/' /usr/local/etc/php/conf.d/docker-php-upload.ini && \
    sed -i 's/max_execution_time = .*/max_execution_time = 300/' /usr/local/etc/php/conf.d/docker-php-timeout.ini && \
    sed -i 's/max_input_vars = .*/max_input_vars = 10000/' /usr/local/etc/php/conf.d/docker-php-input.ini

# Apache modules
RUN a2enmod rewrite expires headers && \
    apache2ctl -M | grep -q headers_module || a2enmod headers

# Cleanup
RUN apt-get clean && \
    rm -rf /var/lib/apt/lists/*

Drop this Dockerfile in your repo and you get a WordPress image with every extension WooCommerce needs, plus WP-CLI v2.10.0 baked in. No more fighting missing PHP modules after an update. The image is built with multi-stage caching so rebuilds are fast—on my DGX Spark a clean build takes ~45 seconds.


Auto-Install WooCommerce on Startup

#!/bin/bash
set -e

echo "[$(date)] Waiting for WordPress to be ready..."
while [ ! -f /var/www/html/wp-config.php ]; do
  sleep 2
done

echo "[$(date)] Installing WordPress..."
if ! wp core is-installed --path=/var/www/html; then
  wp core install \
    --path=/var/www/html \
    --url="http://localhost:8000" \
    --title="Sovereign Webshop" \
    --admin_user="$WP_ADMIN_USER" \
    --admin_password="$WP_ADMIN_PASSWORD" \
    --admin_email="$WP_ADMIN_EMAIL" \
    --skip-email
fi

echo "[$(date)] Installing WooCommerce..."
wp plugin install woocommerce --path=/var/www/html --activate --version=8.9.0

echo "[$(date)] Setting WooCommerce permalinks..."
wp rewrite structure '/%year%/%monthnum%/%postname%/' --path=/var/www/html --hard

echo "[$(date)] Done."

Name this script docker-entrypoint-custom.sh, make it executable (chmod +x docker-entrypoint-custom.sh), and mount it into your WordPress container at /usr/local/bin/docker-entrypoint-custom.sh. On first boot it installs WordPress 6.4.3 and WooCommerce 8.9.0 automatically; subsequent restarts skip the install path. If you forget to chmod +x, Docker will silently ignore the script and you’ll be staring at a blank /wp-admin screen wondering why WooCommerce isn’t there.


# services/api-bridge/main.py
from fastapi import FastAPI, HTTPException
import requests
import os
import logging

app = FastAPI()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

MATRIX_HOMESERVER = os.getenv("MATRIX_HOMESERVER", "")
MATRIX_ROOM_ID = os.getenv("MATRIX_ROOM_ID", "")
MATRIX_TOKEN = os.getenv("MATRIX_TOKEN", "")
AMAZON_API_HOST = os.getenv("AMAZON_API_HOST", "webservices.amazon.de")
AMAZON_ASSOC_TAG = os.getenv("AMAZON_ASSOC_TAG", "")

@app.get("/health")
def health():
    return {"status": "ok", "version": "1.0.0"}

@app.post("/notify")
def notify(order: dict):
    try:
        payload = {
            "msgtype": "m.text",
            "body": f"🛒 New order #{order.get('id', '?')}: {order.get('billing', {}).get('email', 'unknown')}"
        }
        resp = requests.post(
            f"{MATRIX_HOMESERVER}/_matrix/client/r0/rooms/{MATRIX_ROOM_ID}/send/m.room.message",
            headers={"Authorization": f"Bearer {MATRIX_TOKEN}"},
            json=payload,
            timeout=5
        )
        resp.raise_for_status()
        logger.info("Matrix notification sent")
    except Exception as e:
        logger.error(f"Matrix notification failed: {e}")
        raise HTTPException(status_code=500, detail="Matrix notification failed")
    return {"ok": True}

@app.get("/lookup")
def lookup(asin: str):
    if not AMAZON_ASSOC_TAG:
        raise HTTPException(status_code=400, detail="AMAZON_ASSOC_TAG not set")
    try:
        import torrequest
        with torrequest.TorRequest() as tr:
            resp = tr.get(
                f"https://{AMAZON_API_HOST}/paapi5/getitems",
                json={
                    "ItemIds": [asin],
                    "Resources": ["Images.Primary.Medium", "ItemInfo.Title"],
                    "PartnerType": "Associates",
                    "PartnerTag": AMAZON_ASSOC_TAG
                },
                timeout=10
            )
            return resp.json()
    except ImportError:
        raise HTTPException(status_code=501, detail="Tor support requires torrequest; pip install torrequest")
    except Exception as e:
        raise HTTPException(status_code=502, detail=f"Amazon lookup failed: {e}")

Mount the shared codebase as a read-only volume (/app) and you get a tiny microservice that handles Matrix notifications and affiliate lookups without ever leaving your network. Tor support is built in for Amazon PA API calls; if you don’t have Tor running locally you’ll see ImportError: No module named 'torrequest' and the endpoint will return 501. The service exposes /health at http://localhost:8001/health and /lookup?asin=B08N5KWB9H for product lookups.


Gotchas That Will Bite You

Stack

Sovereign AI Webshop

Self-hosted WooCommerce stack with Docker

8
API Bridge Privacy-first integrations
7
Automation n8n workflow engine
6
Cache Redis object storage
5
Database MariaDB with volumes
4
WordPress WooCommerce with caching
3
Runtime Docker Compose
2
OS Linux ARM64
1
Hardware Raspberry Pi 5/DGX Spark