# Deployment guide — Proxmox LXC (home network) Target architecture: ``` Reverse proxy (existing) innercontext LXC (new, Debian 13) ┌──────────────────────┐ ┌────────────────────────────────────┐ │ reverse proxy │────────────▶│ nginx :80 │ │ innercontext.lan → * │ │ /api/* → uvicorn :8000/* │ └──────────────────────┘ │ /mcp/* → uvicorn :8000/mcp/* │ │ /* → SvelteKit Node :3000 │ └────────────────────────────────────┘ │ │ FastAPI + MCP SvelteKit Node ``` ## 1. Prerequisites - Proxmox VE host with an existing PostgreSQL LXC and a reverse proxy - LAN hostname `innercontext.lan` resolvable on the network (via router DNS or `/etc/hosts`) - The PostgreSQL LXC must accept connections from the innercontext LXC IP --- ## 2. Create the LXC container In the Proxmox UI (or via CLI): ```bash # CLI example — adjust storage, bridge, IP to your environment pct create 200 local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst \ --hostname innercontext \ --cores 2 \ --memory 1024 \ --swap 512 \ --rootfs local-lvm:8 \ --net0 name=eth0,bridge=vmbr0,ip=dhcp \ --unprivileged 1 \ --start 1 ``` Note the container's IP address after it starts (`pct exec 200 -- ip -4 a`). --- ## 3. Container setup ```bash pct enter 200 # or SSH into the container ``` ### System packages ```bash apt update && apt upgrade -y apt install -y git nginx curl ca-certificates gnupg lsb-release ``` ### Python 3.12+ + uv ```bash apt install -y python3 python3-venv curl -LsSf https://astral.sh/uv/install.sh | sh source $HOME/.local/bin/env # or re-login ``` ### Node.js 22 + pnpm ```bash curl -fsSL https://deb.nodesource.com/setup_22.x | bash - apt install -y nodejs npm install -g pnpm ``` ### Application user ```bash useradd --system --create-home --shell /bin/bash innercontext ``` --- ## 4. Create the database on the PostgreSQL LXC Run on the **PostgreSQL LXC**: ```bash psql -U postgres <<'SQL' CREATE USER innercontext WITH PASSWORD 'change-me'; CREATE DATABASE innercontext OWNER innercontext; SQL ``` Edit `/etc/postgresql/18/main/pg_hba.conf` and add (replace `` with the innercontext container IP): ``` host innercontext innercontext /32 scram-sha-256 ``` Then reload: ```bash systemctl reload postgresql ``` --- ## 5. Clone the repository ```bash mkdir -p /opt/innercontext git clone https://github.com/your-user/innercontext.git /opt/innercontext chown -R innercontext:innercontext /opt/innercontext ``` --- ## 6. Backend setup ```bash cd /opt/innercontext/backend ``` ### Install dependencies ```bash sudo -u innercontext uv sync ``` ### Create `.env` ```bash cat > /opt/innercontext/backend/.env <<'EOF' DATABASE_URL=postgresql+psycopg://innercontext:change-me@/innercontext EOF chmod 600 /opt/innercontext/backend/.env chown innercontext:innercontext /opt/innercontext/backend/.env ``` ### Test ```bash sudo -u innercontext bash -c ' cd /opt/innercontext/backend source .env uv run uvicorn main:app --host 127.0.0.1 --port 8000 ' # Ctrl-C after confirming it starts ``` ### Install systemd service ```bash cp /opt/innercontext/systemd/innercontext.service /etc/systemd/system/ systemctl daemon-reload systemctl enable --now innercontext systemctl status innercontext ``` --- ## 7. Frontend build and setup ```bash cd /opt/innercontext/frontend ``` ### Create `.env.production` ```bash cat > /opt/innercontext/frontend/.env.production <<'EOF' PUBLIC_API_BASE=http://innercontext.lan/api EOF chmod 600 /opt/innercontext/frontend/.env.production chown innercontext:innercontext /opt/innercontext/frontend/.env.production ``` ### Install dependencies and build ```bash sudo -u innercontext bash -c ' cd /opt/innercontext/frontend pnpm install PUBLIC_API_BASE=http://innercontext.lan/api pnpm build ' ``` The production build lands in `/opt/innercontext/frontend/build/`. ### Install systemd service ```bash cp /opt/innercontext/systemd/innercontext-node.service /etc/systemd/system/ systemctl daemon-reload systemctl enable --now innercontext-node systemctl status innercontext-node ``` --- ## 8. nginx setup ```bash cp /opt/innercontext/nginx/innercontext.conf /etc/nginx/sites-available/innercontext ln -s /etc/nginx/sites-available/innercontext /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default nginx -t systemctl reload nginx ``` --- ## 9. Reverse proxy configuration Point your existing reverse proxy at the innercontext LXC's nginx (`:80`). Example — Caddy: ``` innercontext.lan { reverse_proxy :80 } ``` Example — nginx upstream: ```nginx server { listen 80; server_name innercontext.lan; location / { proxy_pass http://:80; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ``` Reload your reverse proxy after applying the change. --- ## 10. Verification ```bash # From any machine on the LAN: curl http://innercontext.lan/api/health-check # {"status":"ok"} curl http://innercontext.lan/api/products # [] curl http://innercontext.lan/ # SvelteKit HTML shell curl -N http://innercontext.lan/mcp/mcp # MCP StreamableHTTP endpoint ``` The web UI should be accessible at `http://innercontext.lan`. --- ## 11. Updating the application ```bash cd /opt/innercontext git pull # If backend dependencies changed: cd backend && sudo -u innercontext uv sync && cd .. # Rebuild frontend: cd frontend && sudo -u innercontext bash -c ' pnpm install PUBLIC_API_BASE=http://innercontext.lan/api pnpm build ' systemctl restart innercontext innercontext-node ``` --- ## 12. Troubleshooting ### 502 Bad Gateway on `/api/*` ```bash systemctl status innercontext journalctl -u innercontext -n 50 # Check .env DATABASE_URL is correct and PG LXC accepts connections ``` ### 502 Bad Gateway on `/` ```bash systemctl status innercontext-node journalctl -u innercontext-node -n 50 # Verify /opt/innercontext/frontend/build/index.js exists (pnpm build ran successfully) ``` ### MCP endpoint not responding ```bash # MCP uses SSE — disable buffering is already in nginx config # Verify the backend started successfully: curl http://127.0.0.1:8000/health-check # Check FastAPI logs: journalctl -u innercontext -n 50 ``` ### Database connection refused ```bash # From innercontext LXC: psql postgresql+psycopg://innercontext:change-me@/innercontext -c "SELECT 1" # If it fails, check pg_hba.conf on the PG LXC and verify the IP matches ```