A robust, self-contained Go IRC bot that connects over TLS and exposes a secure, token-authenticated REST API for remote control. Perfect for automation, monitoring, and integration with other services.
- Secure IRC Connection: TLS-enabled IRC connections with optional server password support
- SASL Authentication: Optional SASL PLAIN authentication for IRC networks that require it
- Auto-Reconnect: Intelligent reconnection with exponential backoff for maximum uptime
- REST API: Token-protected HTTP/HTTPS endpoints for complete bot control
- IRC Network Discovery: List channels and get user information via LIST and WHOIS commands
- Flexible Event System: Advanced trigger system supporting multiple IRC events (mentions, joins, parts, mode changes, etc.)
- n8n Integration: Comprehensive n8n node package with both action and trigger nodes
- Multiple Webhooks: Support for multiple trigger endpoints with filtering and authentication
- Channel Management: Join, part, and track channels programmatically
- Message Control: Send messages, notices, and raw IRC commands via API
- Graceful Shutdown: Clean disconnection and resource cleanup
- Zero Dependencies: Self-contained binary with no external dependencies
- Production Ready: Comprehensive logging, error handling, and monitoring endpoints
- Go 1.24 or later
- IRC server with TLS support
- (Optional) TLS certificates for HTTPS API
# Clone the repository
git clone https://github.com/h4ks-com/hanna
cd hanna
# Build from source (no need for go mod tidy - dependencies are all local)
go build -o hanna .
# Or build with specific flags for production
CGO_ENABLED=0 go build -ldflags="-w -s" -o hanna .# Build using Docker
docker build -t hanna-bot .
# Or using docker-compose
docker-compose build hanna-botThe project is organized as a proper Go module:
hanna/
βββ main.go # Main application entry point
βββ irc/ # IRC client package
β βββ client.go # IRC client implementation
β βββ *_test.go # Tests for IRC functionality
βββ go.mod # Go module definition
βββ Dockerfile # Docker build configuration
# Basic setup with HTTP API
API_TOKEN=your_secret_token \
IRC_ADDR=irc.libera.chat:6697 \
IRC_NICK=YourBotName \
./hannaAll configuration is done via environment variables:
| Variable | Description | Default | Required |
|---|---|---|---|
IRC_ADDR |
IRC server address (host:port) | - | β |
IRC_TLS |
Enable TLS connection | 1 |
β |
IRC_TLS_INSECURE |
Skip TLS certificate verification | 0 |
β |
IRC_PASS |
Server password | - | β |
IRC_NICK |
Bot nickname | goircbot |
β |
IRC_USER |
Username/ident | goircbot |
β |
IRC_NAME |
Real name/GECOS | Go IRC Bot |
β |
SASL_USER |
SASL authentication username | - | β |
SASL_PASS |
SASL authentication password | - | β |
AUTOJOIN |
Comma-separated channels to auto-join | - | β |
| Variable | Description | Default | Required |
|---|---|---|---|
API_ADDR |
HTTP/HTTPS listen address | :8080 |
β |
API_TOKEN |
Bearer token for API authentication | - | |
API_TLS |
Enable HTTPS | 0 |
β |
API_CERT |
Path to TLS certificate file | - | |
API_KEY |
Path to TLS private key file | - |
| Variable | Description | Default | Required |
|---|---|---|---|
N8N_WEBHOOK |
Legacy webhook URL for chat integration | - | β |
TRIGGER_CONFIG |
JSON configuration for multiple trigger endpoints | - | β |
The bot supports a flexible trigger system for sending IRC events to multiple endpoints:
Legacy Mode (backward compatible):
export N8N_WEBHOOK="https://n8n.example.com/webhook/irc-bot"Advanced Mode (recommended):
export TRIGGER_CONFIG='{
"endpoints": {
"mentions": {
"url": "https://n8n.example.com/webhook/mentions",
"token": "secret-token-123",
"events": ["mention"],
"channels": ["#support", "#general"]
},
"moderation": {
"url": "https://n8n.example.com/webhook/moderation",
"token": "mod-token-456",
"events": ["join", "part", "kick", "mode"],
"channels": ["#general"]
}
}
}'Supported Event Types:
mention- When the bot is mentionedprivmsg- All channel/private messagesjoin- User joins a channelpart- User leaves a channelquit- User quits IRCkick- User is kicked from channelmode- Mode changes (op, voice, etc.)nick- Nickname changestopic- Channel topic changesnotice- IRC notices
*Required when API_TLS=1
If you have Let's Encrypt certificates for your domain:
export API_TLS=1
export API_CERT=/etc/letsencrypt/live/yourdomain.com/fullchain.pem
export API_KEY=/etc/letsencrypt/live/yourdomain.com/privkey.pem# Generate self-signed certificate
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Use with bot
export API_TLS=1
export API_CERT=cert.pem
export API_KEY=key.pemAll API endpoints (except /health) require a Bearer token:
curl -H "Authorization: Bearer your_secret_token" https://your-server:8080/api/stateGET /healthReturns bot connection status and current nickname.
Response:
{
"ok": true,
"nick": "YourBot"
}GET /api/state
Authorization: Bearer <token>Returns comprehensive bot status including connected channels.
Response:
{
"connected": true,
"nick": "YourBot",
"channels": ["#general", "#bots"]
}POST /api/join
Authorization: Bearer <token>
Content-Type: application/json
{
"channel": "#example"
}POST /api/part
Authorization: Bearer <token>
Content-Type: application/json
{
"channel": "#example",
"reason": "Goodbye!"
}POST /api/send
Authorization: Bearer <token>
Content-Type: application/json
{
"target": "#example",
"message": "Hello, world!"
}POST /api/notice
Authorization: Bearer <token>
Content-Type: application/json
{
"target": "#example",
"message": "This is a notice"
}POST /api/nick
Authorization: Bearer <token>
Content-Type: application/json
{
"nick": "NewBotName"
}POST /api/raw
Authorization: Bearer <token>
Content-Type: application/json
{
"line": "PRIVMSG #channel :Custom message"
}GET /api/list
Authorization: Bearer <token>Response:
{
"channels": [
{
"channel": "#general",
"users": "42",
"topic": "Welcome to the general discussion channel"
},
{
"channel": "#bots",
"users": "15",
"topic": "Bot testing and development"
}
],
"count": 2
}POST /api/whois
Authorization: Bearer <token>
Content-Type: application/json
{
"nick": "username"
}Response:
{
"nick": "username",
"user": "user",
"host": "example.com",
"real_name": "Real Name",
"server": "irc.libera.chat",
"server_info": "Stockholm, Sweden",
"operator": false,
"idle_seconds": "42",
"idle_info": "seconds idle",
"channels": "@#ops +#general #random",
"raw_data": [
{
"type": "user",
"nick": "username",
"user": "user",
"host": "example.com",
"real_name": "Real Name"
}
]
}#!/bin/bash
# Production setup with HTTPS and advanced n8n trigger integration
export API_TOKEN="$(openssl rand -hex 32)"
export API_TLS=1
export API_CERT="/etc/letsencrypt/live/bot.example.com/fullchain.pem"
export API_KEY="/etc/letsencrypt/live/bot.example.com/privkey.pem"
export API_ADDR=":443"
export IRC_ADDR="irc.libera.chat:6697"
export IRC_NICK="MyAwesomeBot"
export IRC_USER="mybot"
export IRC_NAME="My Awesome IRC Bot"
export AUTOJOIN="#general,#bots"
# Advanced trigger configuration for multiple n8n workflows
export TRIGGER_CONFIG='{
"endpoints": {
"mentions": {
"url": "https://n8n.example.com/webhook/bot-mentions",
"token": "mention-token-123",
"events": ["mention"],
"channels": ["#general", "#support"]
},
"moderation": {
"url": "https://n8n.example.com/webhook/moderation",
"token": "mod-token-456",
"events": ["join", "part", "kick", "mode"],
"channels": ["#general"]
},
"private-messages": {
"url": "https://n8n.example.com/webhook/private-chat",
"token": "private-token-789",
"events": ["privmsg"],
"channels": []
}
}
}'
./hannaThe bot provides comprehensive integration with n8n through both legacy webhooks and the new trigger system.
When someone mentions the bot in IRC with @botname message, the bot will automatically call the configured n8n webhook:
{
"eventType": "mention",
"sender": "username",
"target": "#channel",
"message": "hello bot",
"chatInput": "@botname hello bot",
"botNick": "MyAwesomeBot",
"sessionId": "IRC",
"timestamp": 1692345678,
"messageTags": {
"time": "2023-09-01T12:00:00.000Z"
}
}The new trigger system supports multiple IRC events and endpoints:
1. Install the n8n Node Package
# In your n8n installation
npm install n8n-nodes-hanna2. Create Trigger Workflows
- Add "Hanna Bot Trigger" nodes to your workflows
- Configure authentication tokens and event filters
- Copy webhook URLs to your
TRIGGER_CONFIG
3. Event Examples:
User Joins Channel:
{
"eventType": "join",
"sender": "newuser",
"target": "#general",
"message": "",
"botNick": "MyBot",
"timestamp": 1692345678
}Channel Mode Change:
{
"eventType": "mode",
"sender": "operator",
"target": "#general",
"message": "Mode #general +o newop",
"timestamp": 1692345678
}Private Message:
{
"eventType": "privmsg",
"sender": "user123",
"target": "MyBot",
"message": "Hello bot, how are you?",
"chatInput": "Hello bot, how are you?",
"timestamp": 1692345678
}Using the New Trigger Node (Recommended):
- Install
n8n-nodes-hannapackage in your n8n instance - Create a new workflow in n8n
- Add a "Hanna Bot Trigger" node
- Configure:
- Authentication token (create a secure random token)
- Select events you want to monitor (mention, join, part, etc.)
- Optional: Filter by channels or users
- Copy the webhook URL from the trigger node
- Add the URL and token to your bot's
TRIGGER_CONFIG - Add processing nodes (OpenAI, database, notifications, etc.)
- Optionally add "Hanna Bot" action node to send responses back to IRC
Using Legacy Webhook:
- Create a new workflow in n8n
- Add a "Webhook" trigger node
- Set the webhook URL in the
N8N_WEBHOOKenvironment variable - Process the incoming IRC data and respond as needed
- Optionally use the Hanna API to send responses back to IRC
AI-Powered Chat Bot:
Hanna Bot Trigger (mention events)
β OpenAI Chat Completion
β Hanna Bot Send Message
Channel Moderation:
Hanna Bot Trigger (kick, mode events)
β Log to Database
β Send Alert if Spam Detected
β Auto-Ban Repeat Offenders
Welcome System:
Hanna Bot Trigger (join events)
β Check User Database
β Send Welcome Message for New Users
β Assign Roles Based on Rules
Multi-Channel Bot:
Trigger 1: Support Channel (mention, privmsg in #support)
β Route to Support AI
β Log Support Ticket
Trigger 2: General Chat (mention in #general)
β Route to Fun AI
β Random Responses
Mention Examples:
@MyAwesomeBot what's the weather?β Triggers mention event@MyAwesomeBot helpβ Triggers mention eventMyAwesomeBot helloβ Does NOT trigger mention (missing @)@DifferentBot helloβ Does NOT trigger mention (wrong bot name)
Other Event Examples:
- User joins
#generalβ Triggers join event - User types
hello everyonein#generalβ Triggers privmsg event - Operator gives voice to user β Triggers mode event
- User gets kicked from channel β Triggers kick event
# Send a message to a channel
curl -X POST \
-H "Authorization: Bearer your_secret_token" \
-H "Content-Type: application/json" \
-d '{"target": "#general", "message": "Hello from the API!"}' \
https://bot.example.com/api/send
# Check bot status
curl -H "Authorization: Bearer your_secret_token" \
https://bot.example.com/api/state
# Join a new channel
curl -X POST \
-H "Authorization: Bearer your_secret_token" \
-H "Content-Type: application/json" \
-d '{"channel": "#newchannel"}' \
https://bot.example.com/api/joinimport requests
import json
class IRCBotAPI:
def __init__(self, base_url, token):
self.base_url = base_url.rstrip('/')
self.headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
def send_message(self, target, message):
data = {'target': target, 'message': message}
response = requests.post(
f'{self.base_url}/api/send',
headers=self.headers,
json=data
)
return response.json()
def get_status(self):
response = requests.get(
f'{self.base_url}/api/state',
headers=self.headers
)
return response.json()
# Usage
bot = IRCBotAPI('https://bot.example.com', 'your_secret_token')
bot.send_message('#general', 'Hello from Python!')
status = bot.get_status()
print(f"Bot is {'connected' if status['connected'] else 'disconnected'}")#!/bin/bash
BOT_URL="https://bot.example.com"
BOT_TOKEN="your_secret_token"
send_irc_message() {
local channel="$1"
local message="$2"
curl -s -X POST \
-H "Authorization: Bearer $BOT_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"target\": \"$channel\", \"message\": \"$message\"}" \
"$BOT_URL/api/send"
}
# Send system status to IRC
LOAD=$(uptime | awk -F'load average:' '{print $2}')
send_irc_message "#monitoring" "Server load: $LOAD"The easiest way to run Hanna is using Docker Compose with the included configuration:
-
Copy environment template:
cp .env.example .env
-
Configure your bot: Edit
.envand set at least:IRC_ADDR=irc.libera.chat:6697 IRC_NICK=YourBotName API_TOKEN=your-secure-token-here AUTOJOIN=#your-channels -
Start the services:
docker compose up -d
This will start both Hanna IRC bot and n8n for workflow automation. The bot will be available at http://localhost:8080 and n8n at http://localhost:5678.
The included compose.yaml provides:
- Hanna IRC Bot: Main bot service with API
- n8n: Workflow automation platform for chat processing
- n8n Workflow Loader: Sidecar container that automatically loads workflows on startup
- Automatic networking: Bot can communicate with n8n via
http://n8n:5678 - Persistent storage: n8n workflows and data are preserved
- Environment-based config: All settings from
.envfile
The Docker Compose setup includes a workflow loader that automatically imports workflows into n8n:
- Default Echo Bot: A pre-configured workflow that echoes IRC messages
- Auto-Import: Workflows in
n8n-workflow-loader/workflows/are loaded on startup - Skip Existing: Already-imported workflows are detected and skipped
- Auto-Activation: Imported workflows are automatically activated
- Trigger Integration: The bot's
TRIGGER_CONFIGis automatically configured
Adding Custom Workflows:
- Place workflow JSON files in
n8n-workflow-loader/workflows/ - Remove the
idfield from the workflow JSON - Restart with
docker-compose up -d
The workflow loader uses the n8n REST API and includes error handling and duplicate detection.
If you prefer to build and run manually:
# Build the image
docker build -t hanna-bot .
# Run with environment variables
docker run -d \
--name hanna \
-p 8080:8080 \
-e API_TOKEN=your_secret_token \
-e IRC_ADDR=irc.libera.chat:6697 \
-e IRC_NICK=DockerBot \
-e AUTOJOIN="#general,#bots" \
hanna-botCreate /etc/systemd/system/hanna.service:
[Unit]
Description=Hanna IRC Bot
After=network.target
[Service]
Type=simple
User=ircd
Group=ircd
WorkingDirectory=/opt/hanna
ExecStart=/opt/hanna/hanna
EnvironmentFile=/opt/hanna/.env
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetEnvironment file /opt/hanna/.env:
API_TOKEN=your_secret_token
API_TLS=1
API_CERT=/etc/letsencrypt/live/bot.example.com/fullchain.pem
API_KEY=/etc/letsencrypt/live/bot.example.com/privkey.pem
IRC_ADDR=irc.libera.chat:6697
IRC_NICK=HannaBot
AUTOJOIN=#general
# Advanced trigger configuration
TRIGGER_CONFIG={"endpoints":{"mentions":{"url":"https://n8n.example.com/webhook/mentions","token":"secure-token-123","events":["mention"],"channels":["#general","#support"]},"moderation":{"url":"https://n8n.example.com/webhook/moderation","token":"mod-token-456","events":["join","part","kick","mode"],"channels":["#general"]}}}Enable and start:
sudo systemctl enable hanna
sudo systemctl start hanna
sudo systemctl status hannaThe /health endpoint provides a simple way to monitor bot status:
# Check if bot is connected
curl -f https://bot.example.com/health || echo "Bot is down!"Consider extending the bot with Prometheus metrics for comprehensive monitoring.
- API Token: Use a strong, randomly generated token
- HTTPS: Always use HTTPS in production
- Firewall: Restrict API access to trusted networks
- File Permissions: Protect certificate files (0600 permissions)
- Regular Updates: Keep dependencies and certificates updated
Hanna includes a comprehensive n8n node package (n8n-nodes-hanna) that provides both action and trigger nodes for complete IRC automation.
# Install in your n8n instance
npm install n8n-nodes-hanna
# Or install globally
npm install -g n8n-nodes-hanna- Send messages and notices to IRC channels
- Join and part channels programmatically
- Change bot nickname
- Send raw IRC commands
- Get bot status and connected channels
- Webhook-based trigger for IRC events
- Configurable event filtering (mention, join, part, etc.)
- Channel and user filtering
- Authentication token validation
- Support for multiple simultaneous triggers
- Add "Hanna Bot" node to your workflow
- Configure credentials:
- API URL:
https://your-bot.example.com - API Token: Your bot's API token
- API URL:
- Select operation (Send Message, Join Channel, etc.)
- Configure target and message parameters
- Add "Hanna Bot Trigger" node to your workflow
- Set authentication token (secure random string)
- Select IRC events to monitor
- Optional: Set channel/user filters
- Copy webhook URL to bot's
TRIGGER_CONFIG
See the Advanced Workflow Examples section above for complete workflow configurations using both trigger and action nodes.
# Run all tests
go test -v- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run
go test -vto ensure all tests pass - Submit a pull request
This project is licensed under the GPLv3 License - see the LICENSE file for details.
Bot won't connect to IRC:
- Check
IRC_ADDRformat (must include port) - Verify TLS settings match server requirements
- Check firewall/network connectivity
API returns 401 Unauthorized:
- Verify
API_TOKENis set and matches request - Check
Authorizationheader format:Bearer <token>
HTTPS certificate errors:
- Verify certificate and key file paths
- Check file permissions
- Ensure certificate is valid and not expired
Bot keeps reconnecting:
- Check IRC server logs for connection issues
- Verify SASL credentials if using authentication
- Check for nick conflicts
For detailed logging, you can modify the log level in the source code or redirect output:
./hanna 2>&1 | tee bot.logBuilt with β€οΈ in Go