GitHunt
AI

aivuk/talk-to-me

A minimal web chat bridge. Visitors on your website send messages; you receive them via Matrix and reply from Element (or any Matrix client). Each visitor gets a dedicated Matrix room.

talk-to-me

A minimal web chat bridge. Visitors on your website send messages; you receive them via Matrix and reply from Element (or any Matrix client). Each visitor gets a dedicated Matrix room.


Requirements

  • A Linux server with Apache and a valid TLS certificate
  • Node.js v22+ (recommend nvm)
  • A Matrix homeserver — this setup uses tuwunel, a lightweight Rust-based server
  • Element (or any Matrix client) on your phone/desktop to receive and reply to messages

1. Matrix homeserver (tuwunel)

Install

Download the latest .deb from the tuwunel releases page and install it:

wget https://github.com/girlbossceo/tuwunel/releases/latest/download/tuwunel_amd64.deb
sudo dpkg -i tuwunel_amd64.deb

Configure

Edit /etc/tuwunel/tuwunel.toml:

[global]
server_name        = "yourdomain.com"
database_path      = "/var/lib/tuwunel"
address            = "127.0.0.1"
port               = 8008
allow_registration = true        # set to false after creating accounts
allow_federation   = false

[global.well_known]
client = "https://matrix.yourdomain.com"
server = "matrix.yourdomain.com:443"

The server_name controls user IDs (e.g. @you:yourdomain.com). The homeserver itself runs at matrix.yourdomain.com via Apache proxy — see section 4.

Start

sudo systemctl enable --now tuwunel

Create accounts

# Owner account (you)
curl -X POST http://localhost:8008/_matrix/client/v3/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"you","password":"your-password","kind":"user"}'

# Bot account (the bridge)
curl -X POST http://localhost:8008/_matrix/client/v3/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"bot","password":"your-bot-password","kind":"user"}'

Then disable registration in tuwunel.toml (allow_registration = false) and restart:

sudo systemctl restart tuwunel

2. Backend

Clone and install

git clone https://github.com/youruser/talk-to-me.git
cd talk-to-me/backend
npm install

Configure

Copy the example env file and fill in your values:

cp ../.env.example ../.env
nano ../.env
MATRIX_HOMESERVER_URL=http://127.0.0.1:8008
MATRIX_BOT_USER=@bot:yourdomain.com
MATRIX_BOT_PASSWORD=your-bot-password
MATRIX_OWNER_USER=@you:yourdomain.com

Lock down the file:

chmod 600 ../.env

Create the data directory

mkdir -p ../data

Run as a systemd service

Copy the service file and edit paths if needed:

sudo cp /path/to/talk-to-me.service /etc/systemd/system/talk-to-me.service
sudo systemctl daemon-reload
sudo systemctl enable --now talk-to-me

Example service file (/etc/systemd/system/talk-to-me.service):

[Unit]
Description=talk-to-me Matrix chat bridge
After=network.target tuwunel.service
Requires=tuwunel.service

[Service]
Type=simple
User=youruser
WorkingDirectory=/home/youruser/talk-to-me/backend
EnvironmentFile=/home/youruser/talk-to-me/.env
ExecStart=/home/youruser/.nvm/versions/node/v22.18.0/bin/node index.js
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Adjust the node path to match your installation (which node or node --version to verify).


3. Frontend

Copy the frontend files to your web root:

sudo cp -r frontend/ /var/www/yoursite/

The chat lives in frontend/index.html. The Geist font is included in frontend/fonts/Geist.woff2.


4. Apache configuration

You need two virtual hosts: one for the main site (yourdomain.com) and one for the Matrix homeserver (matrix.yourdomain.com).

yourdomain.com — proxy the API and Matrix well-known

Add inside the :443 VirtualHost:

# Chat backend API
ProxyPass        /api  http://127.0.0.1:3000/api
ProxyPassReverse /api  http://127.0.0.1:3000/api

# Matrix well-known delegation (lets clients discover matrix.yourdomain.com)
ProxyPass        /.well-known/matrix  http://127.0.0.1:8008/.well-known/matrix
ProxyPassReverse /.well-known/matrix  http://127.0.0.1:8008/.well-known/matrix

matrix.yourdomain.com — proxy the Matrix homeserver

<VirtualHost *:443>
  ServerName matrix.yourdomain.com

  SSLEngine on
  SSLCertificateFile    /etc/letsencrypt/live/yourdomain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem

  ProxyPass        / http://127.0.0.1:8008/
  ProxyPassReverse / http://127.0.0.1:8008/
</VirtualHost>

Enable required modules and reload:

sudo a2enmod proxy proxy_http
sudo systemctl reload apache2

Owner commands

Send these as plain text messages from Element in any visitor's room:

Command Effect
rename: "Name" Renames the room and shows the name as a sticky header in the visitor's chat
info Re-sends the visitor's IP, location, browser, and device to the room
dark Switches the visitor's UI to dark mode
light Switches the visitor's UI to light mode
block Blocks the visitor's IP — they see "you are blocked" and cannot send new messages
unblock Unblocks the visitor's IP — their UI restores automatically within ~3 seconds

Directory structure

talk-to-me/
├── .env                  # credentials (never commit — see .env.example)
├── .env.example          # template
├── README.md
├── ARCHITECTURE.md       # detailed technical documentation
├── backend/
│   ├── index.js          # Express server + Matrix sync loop
│   ├── matrix.js         # Matrix REST API wrapper
│   ├── db.js             # SQLite schema and queries
│   └── package.json
├── frontend/
│   ├── index.html        # entire frontend (single file)
│   └── fonts/
│       └── Geist.woff2   # self-hosted variable font (MIT, Vercel)
└── data/
    └── sessions.db       # SQLite database (auto-created, gitignored)

Updating

git pull
cd backend && npm install
sudo systemctl restart talk-to-me
sudo cp ../frontend/index.html /var/www/yoursite/index.html