User Tools

Site Tools


computing:librechat

This is an old revision of the document!


Here is the converted DokuWiki-based markdown for the LibreChat setup tutorial.

```markdown

LibreChat Complete Setup Tutorial

Addressed to: Libre

Domain: chat.haacksnetworking.org Stack: Debian 13, npm (no Docker for LibreChat), Apache reverse proxy, PM2, MongoDB 8.0, DeepInfra DeepSeek V4 Flash, custom MCP document tools (docx, xlsx, pdf, pptx).

1. Prerequisites

sudo apt update && sudo apt upgrade -y
sudo apt install -y git build-essential curl gnupg python3-pip python3-venv

Node.js 24

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
sudo npm install -g npm@11
node -v && npm -v

MongoDB 8.0 (Debian 13 uses Bookworm repo)

wget -qO - https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update
sudo apt install -y mongodb-org
sudo systemctl enable --now mongod

PM2

sudo npm install -g pm2

2. Install LibreChat

cd /opt
sudo git clone https://github.com/LibreChat-AI/LibreChat.git
sudo chown -R $USER:$USER LibreChat
cd LibreChat
cp .env.example .env
nano .env

Essential .env values:

MONGO_URI=mongodb://127.0.0.1:27017/LibreChat
 
JWT_SECRET=your_64_hex_secret
JWT_REFRESH_SECRET=your_64_hex_secret
CREDS_KEY=your_64_hex_secret
CREDS_IV=your_32_hex_iv
 
DOMAIN_CLIENT=https://chat.haacksnetworking.org
DOMAIN_SERVER=https://chat.haacksnetworking.org
 
TRUST_PROXY=1
HOST=127.0.0.1
 
DEEPINFRA_API_KEY=sk-di-your_key_here

Generate secrets with openssl rand -hex 32 (and openssl rand -hex 16 for the IV).

npm run reinstall
npm run backend          # test once, then Ctrl+C
pm2 start npm --name librechat -- run backend
pm2 save
pm2 startup              # follow the printed command

3. Apache Reverse Proxy + HTTPS

Modules

sudo a2enmod proxy proxy_http proxy_wstunnel ssl rewrite headers socache_shmcb
sudo systemctl restart apache2

Certificate

sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache -d chat.haacksnetworking.org

VirtualHost

<VirtualHost *:443>
    ServerName chat.haacksnetworking.org
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/chat.haacksnetworking.org/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/chat.haacksnetworking.org/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
 
    ProxyPreserveHost On
    ProxyRequests Off
 
    # Exclude downloads from proxy (must come before ProxyPass /)
    ProxyPass /downloads !
    Alias /downloads /opt/LibreChat/generated_docs
    <Directory /opt/LibreChat/generated_docs>
        Options -Indexes
        Require all granted
    </Directory>
 
    ProxyPass / http://127.0.0.1:3080/
    ProxyPassReverse / http://127.0.0.1:3080/
 
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"
    RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
    RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
 
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) "ws://127.0.0.1:3080/$1" [P,L]
 
    ProxyTimeout 300
    Timeout 300
    LimitRequestBody 26214400
 
    ErrorLog ${APACHE_LOG_DIR}/librechat-error.log
    CustomLog ${APACHE_LOG_DIR}/librechat-access.log combined
</VirtualHost>
 
<VirtualHost *:80>
    ServerName chat.haacksnetworking.org
    Redirect permanent / https://chat.haacksnetworking.org/
</VirtualHost>
sudo a2ensite librechat
sudo apache2ctl configtest
sudo systemctl reload apache2

Firewall

sudo ufw allow OpenSSH
sudo ufw allow 'Apache Full'
sudo ufw enable

4. librechat.yaml (DeepSeek + Web Search + MCP)

Create or edit /opt/LibreChat/librechat.yaml:

version: 1.3.17
cache: true

endpoints:
  custom:
    - name: "DeepInfra DeepSeek"
      apiKey: "${DEEPINFRA_API_KEY}"
      baseURL: "https://api.deepinfra.com/v1/openai"
      models:
        default: ["deepseek-ai/DeepSeek-V4-Flash"]
        fetch: false
      titleConvo: true
      titleModel: "deepseek-ai/DeepSeek-V4-Flash"
      modelDisplayLabel: "DeepSeek V4 Flash"

webSearch:
  searchProvider: "keenable"
  scraperProvider: "keenable"
  rerankerType: "none"

mcpServers:
  document-tools:
    type: stdio
    command: /opt/mcp-docs/venv/bin/python
    args:
      - /opt/mcp-docs/server.py
    timeout: 60000

5. MCP Document-Tools Server (docx, xlsx, pdf, pptx)

cd /opt
mkdir -p /opt/mcp-docs
cd /opt/mcp-docs
python3 -m venv venv
source venv/bin/activate
pip install mcp python-docx openpyxl pandas reportlab python-pptx

Create /opt/mcp-docs/server.py:

#!/usr/bin/env python3
import json
import os
from mcp.server import MCPServer
from docx import Document
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from pptx import Presentation
 
OUTPUT_DIR = "/opt/LibreChat/generated_docs"
os.makedirs(OUTPUT_DIR, exist_ok=True)
 
mcp = MCPServer("document-tools")
 
@mcp.tool()
def create_docx(title: str, content: list = None, body: str = None) -> str:
    """Create a Word (.docx) document.
    Prefer content as a list of objects: [{"type":"heading|paragraph|bullet", "text":"..."}].
    If that fails, pass body as a plain multi-line string.
    """
    doc = Document()
    doc.add_heading(title, 0)
 
    items = content or []
    if not items and body:
        for line in body.splitlines():
            line = line.strip()
            if not line:
                continue
            if line.startswith("#"):
                doc.add_heading(line.lstrip("# ").strip(), level=1)
            elif line.startswith("- ") or line.startswith("* "):
                doc.add_paragraph(line[2:].strip(), style="List Bullet")
            else:
                doc.add_paragraph(line)
    else:
        for item in items:
            if isinstance(item, str):
                doc.add_paragraph(item)
                continue
            if not isinstance(item, dict):
                continue
            t = (item.get("type") or "paragraph").lower()
            text = item.get("text") or item.get("content") or ""
            if not text:
                continue
            if t == "heading":
                doc.add_heading(text, level=1)
            elif t == "bullet":
                doc.add_paragraph(text, style="List Bullet")
            else:
                doc.add_paragraph(text)
 
    filename = f"{title.replace(' ', '_')}.docx"
    path = os.path.join(OUTPUT_DIR, filename)
    doc.save(path)
    return json.dumps({
        "success": True,
        "file": filename,
        "download": f"https://chat.haacksnetworking.org/downloads/{filename}"
    })
 
@mcp.tool()
def create_xlsx(name: str, headers: list, rows: list) -> str:
    """Create an Excel (.xlsx) spreadsheet."""
    wb = Workbook()
    ws = wb.active
    ws.title = name[:31]
    for col, h in enumerate(headers, 1):
        cell = ws.cell(1, col, h)
        cell.font = Font(bold=True, color="FFFFFF")
        cell.fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid")
    for r_idx, row in enumerate(rows, 2):
        for c_idx, val in enumerate(row, 1):
            ws.cell(r_idx, c_idx, val)
    filename = f"{name.replace(' ', '_')}.xlsx"
    path = os.path.join(OUTPUT_DIR, filename)
    wb.save(path)
    return json.dumps({
        "success": True,
        "file": filename,
        "download": f"https://chat.haacksnetworking.org/downloads/{filename}"
    })
 
@mcp.tool()
def create_pdf(title: str, content: list = None, body: str = None) -> str:
    """Create a PDF document. content is a list of dicts with type (heading/paragraph/bullet) and text, or pass body as plain text."""
    filename = f"{title.replace(' ', '_')}.pdf"
    path = os.path.join(OUTPUT_DIR, filename)
    doc = SimpleDocTemplate(path, pagesize=letter)
    styles = getSampleStyleSheet()
    story = []
 
    story.append(Paragraph(title, styles["Title"]))
    story.append(Spacer(1, 12))
 
    items = content or []
    if not items and body:
        for line in body.splitlines():
            line = line.strip()
            if not line:
                continue
            if line.startswith("#"):
                story.append(Paragraph(line.lstrip("# ").strip(), styles["Heading2"]))
            elif line.startswith("- ") or line.startswith("* "):
                story.append(Paragraph(f"• {line[2:].strip()}", styles["Normal"]))
            else:
                story.append(Paragraph(line, styles["Normal"]))
            story.append(Spacer(1, 6))
    else:
        for item in items:
            if isinstance(item, str):
                story.append(Paragraph(item, styles["Normal"]))
                story.append(Spacer(1, 6))
                continue
            if not isinstance(item, dict):
                continue
            t = (item.get("type") or "paragraph").lower()
            text = item.get("text") or item.get("content") or ""
            if not text:
                continue
            if t == "heading":
                story.append(Paragraph(text, styles["Heading2"]))
            elif t == "bullet":
                story.append(Paragraph(f"• {text}", styles["Normal"]))
            else:
                story.append(Paragraph(text, styles["Normal"]))
            story.append(Spacer(1, 6))
 
    doc.build(story)
    return json.dumps({
        "success": True,
        "file": filename,
        "download": f"https://chat.haacksnetworking.org/downloads/{filename}"
    })
 
@mcp.tool()
def create_pptx(title: str, slides: list = None) -> str:
    """Create a PowerPoint (.pptx). slides is a list of dicts with title and content (list of bullet strings)."""
    prs = Presentation()
    title_slide_layout = prs.slide_layouts[0]
    slide = prs.slides.add_slide(title_slide_layout)
    slide.shapes.title.text = title
    if len(slide.placeholders) > 1:
        try:
            slide.placeholders[1].text = "Generated by LibreChat"
        except Exception:
            pass
 
    bullet_layout = prs.slide_layouts[1]
    for s in (slides or []):
        slide = prs.slides.add_slide(bullet_layout)
        slide.shapes.title.text = s.get("title", "Slide")
        body = slide.placeholders[1]
        tf = body.text_frame
        tf.text = ""
        for bullet in s.get("content", []):
            p = tf.add_paragraph()
            p.text = str(bullet)
            p.level = 0
 
    filename = f"{title.replace(' ', '_')}.pptx"
    path = os.path.join(OUTPUT_DIR, filename)
    prs.save(path)
    return json.dumps({
        "success": True,
        "file": filename,
        "download": f"https://chat.haacksnetworking.org/downloads/{filename}"
    })
 
if __name__ == "__main__":
    mcp.run(transport="stdio")
chmod +x /opt/mcp-docs/server.py
mkdir -p /opt/LibreChat/generated_docs
deactivate

Restart LibreChat:

pm2 restart librechat

6. Using the Tools

  • In a chat, open the tools / MCP menu.
  • Add or enable the document-tools MCP server.
  • Ask for a document. Available tools:
    • create_docx — Word
    • create_xlsx — Excel
    • create_pdf — PDF
    • create_pptx — PowerPoint

Example prompts:

  • “Create a Word document titled 'Solar System' with paragraphs and bullets about the planets. Give me the download link.”
  • “Make an Excel file named 'Employees' with headers Name, Department, Salary and three sample rows.”
  • “Create a PDF titled 'Monthly Report' with a heading and a few paragraphs.”
  • “Create a PowerPoint titled 'Project Update' with slides for Goals, Progress, and Next Steps.”

Files appear at https://chat.haacksnetworking.org/downloads/….

7. Admin and Registration

First account is admin. Verify:

mongosh --quiet --eval 'db = db.getSiblingDB("LibreChat"); db.users.find({}, {email:1, role:1}).pretty()'

To disable public registration, add to .env:

ALLOW_REGISTRATION=false

Then create users with npm run create-user.

8. Updates

cd /opt/LibreChat
pm2 stop librechat
git pull
npm run smart-reinstall
pm2 restart librechat

Quick Checklist

1. Node 24 + MongoDB (Bookworm repo)
2. Clone → ''.env'' (secrets, domains, HOST, DeepInfra key) → ''npm run reinstall''
3. PM2
4. Apache modules + Certbot + VirtualHost (with ''ProxyPass /downloads !'' + Alias)
5. ''librechat.yaml'' (DeepSeek + webSearch + mcpServers)
6. MCP server in ''/opt/mcp-docs'' with docx / xlsx / pdf / pptx tools
7. Restart LibreChat and enable the document-tools MCP server in chat

This is the full working configuration. ```

computing/librechat.1792261849.txt.gz · Last modified: by oemb1905