1340 lines
32 KiB
YAML
1340 lines
32 KiB
YAML
# UnrealIRCd + Anope IRC Services + The Lounge web client
|
|
# ArgoCD managed - BlueJay Lab
|
|
# Credentials: 1Password → OnePasswordItem → K8s Secret → initContainer sed injection
|
|
---
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: irc
|
|
labels:
|
|
app.kubernetes.io/part-of: bluejay-infra
|
|
---
|
|
# 1Password → K8s Secret sync
|
|
apiVersion: onepassword.com/v1
|
|
kind: OnePasswordItem
|
|
metadata:
|
|
name: irc-credentials
|
|
namespace: irc
|
|
spec:
|
|
itemPath: "vaults/IAmWorkin/items/IRC UnrealIRCd"
|
|
---
|
|
# TLS Certificate for IRC
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: irc-tls
|
|
namespace: irc
|
|
spec:
|
|
secretName: irc-tls
|
|
issuerRef:
|
|
name: step-ca-acme
|
|
kind: ClusterIssuer
|
|
dnsNames:
|
|
- irc.iamworkin.lan
|
|
---
|
|
# TLS Certificate for The Lounge web IRC
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: webirc-tls
|
|
namespace: irc
|
|
spec:
|
|
secretName: webirc-tls
|
|
issuerRef:
|
|
name: step-ca-acme
|
|
kind: ClusterIssuer
|
|
dnsNames:
|
|
- webirc.iamworkin.lan
|
|
---
|
|
# The Lounge configuration
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: thelounge-config
|
|
namespace: irc
|
|
data:
|
|
config.js: |
|
|
"use strict";
|
|
|
|
module.exports = {
|
|
public: true,
|
|
host: "0.0.0.0",
|
|
port: 9000,
|
|
reverseProxy: true,
|
|
maxHistory: 2500,
|
|
theme: "thelounge-theme-flowercore",
|
|
prefetch: false,
|
|
disableMediaPreview: true,
|
|
fileUpload: {
|
|
enable: false
|
|
},
|
|
defaults: {
|
|
name: "BlueJayIRC",
|
|
host: "unrealircd.irc.svc.cluster.local",
|
|
port: 6667,
|
|
password: "",
|
|
tls: false,
|
|
rejectUnauthorized: true,
|
|
nick: "BlueJayWeb%%",
|
|
username: "bluejayweb",
|
|
realname: "BlueJay Web IRC",
|
|
join: "#general"
|
|
},
|
|
lockNetwork: true,
|
|
leaveMessage: "BlueJay Web IRC"
|
|
};
|
|
---
|
|
# FlowerCore / Blue Jay theme package for The Lounge
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: thelounge-flowercore-theme
|
|
namespace: irc
|
|
data:
|
|
package.json: |
|
|
{
|
|
"name": "thelounge-theme-flowercore",
|
|
"version": "1.0.0",
|
|
"description": "FlowerCore Blue Jay theme for The Lounge",
|
|
"main": "package.json",
|
|
"keywords": [
|
|
"thelounge",
|
|
"thelounge-theme"
|
|
],
|
|
"thelounge": {
|
|
"type": "theme",
|
|
"name": "FlowerCore Blue Jay",
|
|
"css": "theme.css",
|
|
"files": [
|
|
"bluejay-logo.svg",
|
|
"bluejay-bg.svg"
|
|
]
|
|
}
|
|
}
|
|
theme.css: |
|
|
:root {
|
|
--fc-bg: #0a1628;
|
|
--fc-surface: #111d33;
|
|
--fc-surface-2: #162844;
|
|
--fc-border: #1e3a5f;
|
|
--fc-accent: #2b8aff;
|
|
--fc-accent-soft: rgba(43, 138, 255, 0.22);
|
|
--fc-gold: #ffb300;
|
|
--fc-text: #e8edf5;
|
|
--fc-text-muted: #9db1c8;
|
|
--fc-success: #3db86a;
|
|
--fc-danger: #e84545;
|
|
--body-color: var(--fc-text);
|
|
--body-color-muted: var(--fc-text-muted);
|
|
--body-bg-color: var(--fc-bg);
|
|
--button-color: var(--fc-accent);
|
|
--button-text-color-hover: #ffffff;
|
|
--overlay-bg-color: rgba(5, 12, 22, 0.84);
|
|
--link-color: #8bc3ff;
|
|
--window-bg-color: var(--fc-surface);
|
|
--window-heading-color: #f5f8ff;
|
|
--date-marker-color: rgba(43, 138, 255, 0.45);
|
|
--unread-marker-color: rgba(255, 179, 0, 0.6);
|
|
--highlight-bg-color: rgba(43, 138, 255, 0.12);
|
|
--highlight-border-color: var(--fc-gold);
|
|
--upload-progressbar-color: var(--fc-gold);
|
|
}
|
|
|
|
body {
|
|
background:
|
|
radial-gradient(circle at top right, rgba(43, 138, 255, 0.22), transparent 30%),
|
|
linear-gradient(145deg, rgba(10, 22, 40, 0.98), rgba(12, 25, 46, 0.98)),
|
|
url("/packages/thelounge-theme-flowercore/bluejay-bg.svg");
|
|
color: var(--fc-text);
|
|
font-family: "Trebuchet MS", "Segoe UI", Verdana, sans-serif;
|
|
}
|
|
|
|
a,
|
|
a:focus,
|
|
a:hover {
|
|
color: var(--link-color);
|
|
}
|
|
|
|
.window,
|
|
#confirm-dialog,
|
|
#context-menu,
|
|
.mentions-popup,
|
|
.textcomplete-menu {
|
|
background: rgba(17, 29, 51, 0.97);
|
|
border: 1px solid var(--fc-border);
|
|
box-shadow: 0 24px 60px rgba(3, 10, 18, 0.55);
|
|
}
|
|
|
|
#loading .window,
|
|
#confirm-dialog {
|
|
background:
|
|
linear-gradient(180deg, rgba(14, 30, 54, 0.98), rgba(17, 29, 51, 0.98)),
|
|
url("/packages/thelounge-theme-flowercore/bluejay-bg.svg");
|
|
border-color: rgba(43, 138, 255, 0.4);
|
|
}
|
|
|
|
#loading .logo,
|
|
#loading .logo-inverted,
|
|
#sidebar .logo,
|
|
#sidebar .logo-inverted {
|
|
display: none !important;
|
|
}
|
|
|
|
#loading-status-container,
|
|
#sidebar .logo-container {
|
|
position: relative;
|
|
}
|
|
|
|
#loading-status-container::before {
|
|
content: "";
|
|
display: block;
|
|
width: 96px;
|
|
height: 96px;
|
|
margin: 0 auto 16px;
|
|
background: url("/packages/thelounge-theme-flowercore/bluejay-logo.svg") center / contain no-repeat;
|
|
filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.45));
|
|
}
|
|
|
|
#loading-page-message::before {
|
|
content: "FlowerCore IRC";
|
|
display: block;
|
|
margin-bottom: 10px;
|
|
color: #ffffff;
|
|
font-size: 30px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.04em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
#loading-page-message::after {
|
|
content: "Blue Jay web chat for iamworkin.lan";
|
|
display: block;
|
|
margin-top: 10px;
|
|
color: var(--fc-text-muted);
|
|
font-size: 14px;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
#loading-page-message {
|
|
color: var(--fc-text);
|
|
font-size: 15px;
|
|
line-height: 1.7;
|
|
max-width: 30rem;
|
|
text-align: center;
|
|
}
|
|
|
|
#sidebar {
|
|
background:
|
|
linear-gradient(180deg, rgba(10, 22, 40, 0.98), rgba(17, 29, 51, 0.98)),
|
|
url("/packages/thelounge-theme-flowercore/bluejay-bg.svg");
|
|
border-right: 1px solid var(--fc-border);
|
|
color: #d5e3f5;
|
|
}
|
|
|
|
#sidebar .logo-container {
|
|
padding: 20px 14px 8px;
|
|
}
|
|
|
|
#sidebar .logo-container::before {
|
|
content: "";
|
|
display: block;
|
|
width: 72px;
|
|
height: 72px;
|
|
margin: 0 auto 10px;
|
|
background: url("/packages/thelounge-theme-flowercore/bluejay-logo.svg") center / contain no-repeat;
|
|
filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.35));
|
|
}
|
|
|
|
#sidebar .logo-container::after {
|
|
content: "FlowerCore IRC";
|
|
display: block;
|
|
color: #ffffff;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.06em;
|
|
text-align: center;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
#sidebar .network {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.channel-list-item,
|
|
#footer button {
|
|
border-radius: 10px;
|
|
transition: background-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
|
|
}
|
|
|
|
.channel-list-item:hover,
|
|
#footer button:hover {
|
|
background: rgba(43, 138, 255, 0.12);
|
|
color: #ffffff;
|
|
}
|
|
|
|
.channel-list-item.active,
|
|
#footer button.active {
|
|
background: linear-gradient(90deg, rgba(43, 138, 255, 0.24), rgba(22, 40, 68, 0.92));
|
|
box-shadow: inset 3px 0 0 var(--fc-gold);
|
|
color: #ffffff;
|
|
}
|
|
|
|
.channel-list-item[data-type="lobby"] {
|
|
color: #8bc3ff;
|
|
}
|
|
|
|
.channel-list-item .badge {
|
|
background: rgba(255, 255, 255, 0.08);
|
|
color: var(--fc-text-muted);
|
|
}
|
|
|
|
.channel-list-item .badge.highlight {
|
|
background: var(--fc-gold);
|
|
color: #08111e;
|
|
font-weight: 700;
|
|
}
|
|
|
|
#footer {
|
|
background: rgba(10, 22, 40, 0.92);
|
|
border-top: 1px solid var(--fc-border);
|
|
}
|
|
|
|
#viewport .lt,
|
|
#viewport .rt,
|
|
#chat button.close,
|
|
#chat button.menu,
|
|
#chat button.mentions,
|
|
#chat button.search,
|
|
#form #submit,
|
|
#form #upload,
|
|
.password-container .reveal-password span {
|
|
color: #8bc3ff;
|
|
}
|
|
|
|
#viewport .lt:hover,
|
|
#viewport .rt:hover,
|
|
#chat button.close:hover,
|
|
#chat button.menu:hover,
|
|
#chat button.mentions:hover,
|
|
#chat button.search:hover,
|
|
#form #submit:hover,
|
|
#form #upload:hover,
|
|
.password-container .reveal-password span:hover {
|
|
background: rgba(43, 138, 255, 0.16);
|
|
border-radius: 8px;
|
|
color: #ffffff;
|
|
opacity: 1;
|
|
}
|
|
|
|
#chat .header {
|
|
background: linear-gradient(135deg, #0e1e36, #1a3a6a, #2b8aff);
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
color: #ffffff;
|
|
}
|
|
|
|
.header .title,
|
|
.header .topic,
|
|
#chat .header button {
|
|
color: #ffffff;
|
|
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
#chat .messages {
|
|
background:
|
|
linear-gradient(180deg, rgba(17, 29, 51, 0.98), rgba(11, 21, 39, 0.98)),
|
|
radial-gradient(circle at top right, rgba(43, 138, 255, 0.08), transparent 35%);
|
|
}
|
|
|
|
#chat .msg {
|
|
border-radius: 6px;
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
#chat .msg:hover {
|
|
background: rgba(255, 255, 255, 0.03);
|
|
}
|
|
|
|
#chat .chat-view[data-type="channel"] .msg.highlight,
|
|
.mentions-popup .msg .content {
|
|
background: linear-gradient(90deg, rgba(43, 138, 255, 0.16), rgba(255, 179, 0, 0.1));
|
|
box-shadow: inset 3px 0 0 var(--fc-gold);
|
|
}
|
|
|
|
#chat .msg-statusmsg {
|
|
background: rgba(255, 179, 0, 0.18);
|
|
color: #ffe4a0;
|
|
}
|
|
|
|
#chat .msg[data-type="monospace_block"] .text {
|
|
background: rgba(8, 17, 30, 0.94);
|
|
border: 1px solid rgba(43, 138, 255, 0.22);
|
|
border-radius: 10px;
|
|
box-shadow: inset 3px 0 0 var(--fc-gold);
|
|
color: var(--fc-text);
|
|
display: inline-block;
|
|
line-height: 1.7;
|
|
max-width: min(100%, 44rem);
|
|
padding: 10px 12px;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
#chat .msg[data-command="motd"] .text {
|
|
background:
|
|
linear-gradient(180deg, rgba(14, 30, 54, 0.96), rgba(8, 17, 30, 0.96)),
|
|
url("/packages/thelounge-theme-flowercore/bluejay-bg.svg");
|
|
border-color: rgba(255, 179, 0, 0.28);
|
|
color: #f4f8ff;
|
|
}
|
|
|
|
#chat .msg[data-command="motd"] .from {
|
|
color: #9dd3ff;
|
|
font-weight: 700;
|
|
}
|
|
|
|
#chat .msg[data-command="motd"] a {
|
|
color: #8bc3ff;
|
|
font-weight: 700;
|
|
}
|
|
|
|
#chat .userlist,
|
|
#form,
|
|
.mentions-popup,
|
|
.textcomplete-menu,
|
|
#context-menu {
|
|
background: rgba(17, 29, 51, 0.98);
|
|
border-color: var(--fc-border);
|
|
}
|
|
|
|
#chat .userlist .count,
|
|
#chat .user-mode:before {
|
|
background: rgba(8, 17, 30, 0.95);
|
|
}
|
|
|
|
.input,
|
|
#connect input,
|
|
#connect select,
|
|
#settings input,
|
|
#settings select,
|
|
#settings textarea,
|
|
#form #nick,
|
|
#chat .userlist .search,
|
|
form.message-search input,
|
|
.jump-to-input .input,
|
|
.password-container input {
|
|
background: rgba(8, 17, 30, 0.72);
|
|
border: 1px solid var(--fc-border);
|
|
border-radius: 10px;
|
|
color: var(--fc-text);
|
|
}
|
|
|
|
#form {
|
|
border-top: 1px solid var(--fc-border);
|
|
padding: 8px;
|
|
}
|
|
|
|
#form #nick {
|
|
color: #8bc3ff;
|
|
line-height: 28px;
|
|
}
|
|
|
|
#form #input {
|
|
margin: 0 8px;
|
|
min-height: 36px;
|
|
padding: 8px 10px;
|
|
}
|
|
|
|
::placeholder,
|
|
.jump-to-input .input::placeholder,
|
|
form.message-search input::placeholder {
|
|
color: rgba(232, 237, 245, 0.45);
|
|
}
|
|
|
|
.jump-to-input:before,
|
|
#chat .count:before {
|
|
color: rgba(232, 237, 245, 0.45);
|
|
}
|
|
|
|
.btn {
|
|
background: linear-gradient(180deg, rgba(24, 62, 112, 0.28), rgba(14, 30, 54, 0.38));
|
|
border-color: var(--fc-accent);
|
|
border-radius: 999px;
|
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
|
color: var(--fc-text);
|
|
letter-spacing: 0.12em;
|
|
}
|
|
|
|
.btn:hover,
|
|
.btn:focus,
|
|
.btn:disabled {
|
|
background: linear-gradient(180deg, #2b8aff, #1c6fe3);
|
|
color: #ffffff;
|
|
}
|
|
|
|
.btn:active,
|
|
.btn:focus,
|
|
.input:focus {
|
|
box-shadow: 0 0 0 3px rgba(43, 138, 255, 0.26);
|
|
}
|
|
|
|
#version-checker,
|
|
#settings .settings-sync-panel,
|
|
#connect .connect-sasl-external {
|
|
background: rgba(8, 17, 30, 0.78);
|
|
border: 1px solid var(--fc-border);
|
|
color: var(--fc-text);
|
|
}
|
|
|
|
#version-checker.loading {
|
|
border-left: 3px solid var(--fc-accent);
|
|
color: #9dd3ff;
|
|
}
|
|
|
|
#version-checker.up-to-date {
|
|
border-left: 3px solid var(--fc-success);
|
|
color: #87e9a9;
|
|
}
|
|
|
|
#version-checker.new-packages,
|
|
#version-checker.new-version {
|
|
border-left: 3px solid var(--fc-gold);
|
|
color: #ffe4a0;
|
|
}
|
|
|
|
#version-checker.error,
|
|
#settings .error,
|
|
#sign-in .error {
|
|
border-left: 3px solid var(--fc-danger);
|
|
color: #ffb3b3;
|
|
}
|
|
|
|
#upload-progressbar {
|
|
box-shadow: 0 0 14px rgba(255, 179, 0, 0.75);
|
|
}
|
|
|
|
::-webkit-scrollbar:hover {
|
|
background-color: rgba(255, 255, 255, 0.04);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:vertical {
|
|
background: linear-gradient(180deg, rgba(43, 138, 255, 0.72), rgba(30, 58, 95, 0.95));
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:vertical:active {
|
|
background: linear-gradient(180deg, rgba(255, 179, 0, 0.85), rgba(43, 138, 255, 0.9));
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
#sidebar {
|
|
box-shadow: 0 0 28px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
#chat .header {
|
|
padding-right: 6px;
|
|
}
|
|
}
|
|
bluejay-logo.svg: |
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
|
<ellipse cx="14" cy="18" rx="10" ry="9" fill="#3B7BC0"/>
|
|
<ellipse cx="12" cy="20" rx="6" ry="6" fill="#C8DFFF"/>
|
|
<path d="M10 14 C8 10, 16 8, 22 12 C24 14, 22 18, 18 18 C14 18, 10 16, 10 14Z" fill="#2B5A8A"/>
|
|
<path d="M12 12.5 L21 11" stroke="#fff" stroke-width="1.5" stroke-linecap="round" opacity="0.7"/>
|
|
<circle cx="22" cy="11" r="6" fill="#3B7BC0"/>
|
|
<path d="M20 6 L22 1 L24 3 L22 7Z" fill="#2B5A8A"/>
|
|
<path d="M21 5 L22.5 2 L23.5 4Z" fill="#5BA3FF"/>
|
|
<path d="M16 14 C18 16, 22 16, 26 14" stroke="#0d1520" stroke-width="1.8" fill="none" stroke-linecap="round"/>
|
|
<circle cx="24" cy="10" r="2" fill="#fff"/>
|
|
<circle cx="24.5" cy="9.5" r="1" fill="#0d1520"/>
|
|
<path d="M27 11 L31 11.5 L27 13Z" fill="#364b6b"/>
|
|
<path d="M4 16 L1 13 L3 17 L1 20 L5 18Z" fill="#2B5A8A"/>
|
|
<circle cx="10" cy="23" r="2" fill="#FFB300"/>
|
|
<circle cx="10" cy="23" r="1" fill="#FFCA40"/>
|
|
</svg>
|
|
bluejay-bg.svg: |
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
|
|
<defs>
|
|
<pattern id="hex" x="0" y="0" width="60" height="52" patternUnits="userSpaceOnUse">
|
|
<path d="M30 0 L60 15 L60 37 L30 52 L0 37 L0 15 Z" fill="none" stroke="rgba(43,138,255,0.04)" stroke-width="0.5"/>
|
|
</pattern>
|
|
</defs>
|
|
<rect width="200" height="200" fill="url(#hex)"/>
|
|
<circle cx="30" cy="0" r="1" fill="rgba(255,179,0,0.06)"/>
|
|
<circle cx="90" cy="0" r="1" fill="rgba(255,179,0,0.06)"/>
|
|
<circle cx="150" cy="0" r="1" fill="rgba(255,179,0,0.06)"/>
|
|
<circle cx="0" cy="52" r="1" fill="rgba(43,138,255,0.06)"/>
|
|
<circle cx="60" cy="52" r="1" fill="rgba(43,138,255,0.06)"/>
|
|
<circle cx="120" cy="52" r="1" fill="rgba(43,138,255,0.06)"/>
|
|
<circle cx="180" cy="52" r="1" fill="rgba(43,138,255,0.06)"/>
|
|
</svg>
|
|
---
|
|
# UnrealIRCd configuration template (passwords replaced by placeholders)
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: unrealircd-config-template
|
|
namespace: irc
|
|
data:
|
|
unrealircd.conf: |
|
|
/* BlueJay Lab IRC - UnrealIRCd 6.x config */
|
|
/* Managed by ArgoCD */
|
|
/* Credentials injected from 1Password at pod startup */
|
|
|
|
include "modules.default.conf";
|
|
include "help/help.conf";
|
|
include "operclass.default.conf";
|
|
include "snomasks.default.conf";
|
|
|
|
loadmodule "cloak_sha256";
|
|
|
|
me {
|
|
name "irc.iamworkin.lan";
|
|
info "BlueJay Lab IRC Server";
|
|
sid 001;
|
|
}
|
|
|
|
admin {
|
|
"BlueJay Lab IRC";
|
|
"admin@iamwork.in";
|
|
}
|
|
|
|
class clients {
|
|
pingfreq 90;
|
|
maxclients 500;
|
|
sendq 200k;
|
|
recvq 8000;
|
|
}
|
|
|
|
class opers {
|
|
pingfreq 90;
|
|
maxclients 50;
|
|
sendq 1M;
|
|
recvq 8000;
|
|
}
|
|
|
|
class servers {
|
|
pingfreq 60;
|
|
connfreq 15;
|
|
maxclients 10;
|
|
sendq 20M;
|
|
}
|
|
|
|
allow {
|
|
mask *;
|
|
class clients;
|
|
maxperip 5;
|
|
}
|
|
|
|
listen {
|
|
ip *;
|
|
port 6667;
|
|
}
|
|
|
|
listen {
|
|
ip *;
|
|
port 6697;
|
|
options { tls; }
|
|
tls-options {
|
|
certificate "/app/conf/tls/server.cert.pem";
|
|
key "/app/conf/tls/server.key.pem";
|
|
}
|
|
}
|
|
|
|
listen {
|
|
ip *;
|
|
port 8067;
|
|
}
|
|
|
|
oper bluejay {
|
|
mask *;
|
|
password "__OPER_PASSWORD__";
|
|
operclass netadmin-with-override;
|
|
class opers;
|
|
}
|
|
|
|
drpass {
|
|
restart "__OPER_PASSWORD__";
|
|
die "__OPER_PASSWORD__";
|
|
}
|
|
|
|
link services.iamworkin.lan {
|
|
incoming {
|
|
mask *;
|
|
}
|
|
password "__LINK_PASSWORD__";
|
|
class servers;
|
|
}
|
|
|
|
ulines {
|
|
services.iamworkin.lan;
|
|
}
|
|
|
|
log {
|
|
source {
|
|
all;
|
|
\\!debug;
|
|
}
|
|
destination {
|
|
channel "#ops";
|
|
}
|
|
}
|
|
|
|
set {
|
|
network-name "BlueJayIRC";
|
|
default-server "irc.iamworkin.lan";
|
|
services-server "services.iamworkin.lan";
|
|
stats-server "stats.iamworkin.lan";
|
|
help-channel "#general";
|
|
cloak-keys {
|
|
"ZWKeb8YevNiL45Xdh2p5u4tv2xksWgb8YPQSvmerBmNObyGbTDGnU4PNomZaLbZ1D9M2Cy6njM1XLJUkJhAx1oY3coBdZoPykEo7";
|
|
"KqRaLeA6ijOnWDdCqYtJ6rb1VgR8lYnU9Sey7cbRhi3PsGzD5gZONJXyUdbJ7bD26QKCuiDydBsccUVKC3lYN0HJ9sGTlOYR3c2m";
|
|
"2I4oopLDY79Fr4Mucy63EVOfkelVV23nESPWoqMnP1pUc8Yg0D4RK1mVtxyEhdTPpLFyKgG4fRlb6R33eHoQe7yi7moOu4W1Waw6";
|
|
}
|
|
kline-address "admin@iamwork.in";
|
|
maxchannelsperuser 25;
|
|
anti-flood {
|
|
everyone {
|
|
connect-flood 3:60;
|
|
}
|
|
}
|
|
options {
|
|
hide-ulines;
|
|
show-connect-info;
|
|
}
|
|
|
|
/* TLS config */
|
|
tls {
|
|
certificate "/app/conf/tls/server.cert.pem";
|
|
key "/app/conf/tls/server.key.pem";
|
|
trusted-ca-file "/etc/ssl/certs/ca-certificates.crt";
|
|
}
|
|
|
|
/* Allow plaintext for server-to-server links (Anope is internal) */
|
|
plaintext-policy {
|
|
server allow;
|
|
}
|
|
}
|
|
ircd.motd: |
|
|
- BlueJay IRC -
|
|
Welcome to BlueJayIRC on iamworkin.lan.
|
|
|
|
Web IRC: https://webirc.iamworkin.lan
|
|
Channels: #general, #ops, #alerts
|
|
|
|
Keep it keyboard-first, practical, and kind.
|
|
Managed from bluejay-infra via ArgoCD.
|
|
---
|
|
# Anope configuration template (passwords replaced by placeholders)
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: anope-config-template
|
|
namespace: irc
|
|
data:
|
|
services.conf: |
|
|
define
|
|
{
|
|
name = "services.host"
|
|
value = "services.iamworkin.lan"
|
|
}
|
|
|
|
uplink
|
|
{
|
|
host = "unrealircd.irc.svc.cluster.local"
|
|
port = 8067
|
|
password = "__LINK_PASSWORD__"
|
|
}
|
|
|
|
serverinfo
|
|
{
|
|
name = "services.iamworkin.lan"
|
|
description = "BlueJay IRC Services"
|
|
pid = "/anope/data/services.pid"
|
|
motd = "/anope/data/services.motd"
|
|
}
|
|
|
|
module { name = "unreal4" }
|
|
|
|
networkinfo
|
|
{
|
|
networkname = "BlueJayIRC"
|
|
nicklen = 31
|
|
userlen = 10
|
|
hostlen = 64
|
|
chanlen = 32
|
|
}
|
|
|
|
options
|
|
{
|
|
casemap = "ascii"
|
|
strictpasswords = yes
|
|
readtimeout = 5s
|
|
warningtimeout = 4h
|
|
}
|
|
|
|
module { name = "enc_sha256" }
|
|
|
|
/* Service pseudo-client definitions */
|
|
service
|
|
{
|
|
nick = "NickServ"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "Nickname Registration Service"
|
|
}
|
|
|
|
service
|
|
{
|
|
nick = "ChanServ"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "Channel Registration Service"
|
|
}
|
|
|
|
service
|
|
{
|
|
nick = "OperServ"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "Operator Service"
|
|
}
|
|
|
|
service
|
|
{
|
|
nick = "BotServ"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "Bot Service"
|
|
}
|
|
|
|
service
|
|
{
|
|
nick = "HostServ"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "vHost Service"
|
|
}
|
|
|
|
service
|
|
{
|
|
nick = "MemoServ"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "Memo Service"
|
|
}
|
|
|
|
service
|
|
{
|
|
nick = "Global"
|
|
user = "services"
|
|
host = "services.host"
|
|
gecos = "Global Noticer"
|
|
}
|
|
|
|
/* Module configurations */
|
|
module
|
|
{
|
|
name = "nickserv"
|
|
client = "NickServ"
|
|
defaults = "kill_quick ns_secure ns_private hide_email"
|
|
registration = "none"
|
|
expire = 90d
|
|
}
|
|
|
|
module { name = "ns_identify" }
|
|
module { name = "ns_register" }
|
|
module { name = "ns_set" }
|
|
module { name = "ns_drop" }
|
|
module { name = "ns_recover" }
|
|
module { name = "ns_info" }
|
|
module { name = "ns_list" }
|
|
module { name = "ns_access" }
|
|
module { name = "ns_group" }
|
|
|
|
module
|
|
{
|
|
name = "chanserv"
|
|
client = "ChanServ"
|
|
defaults = "keeptopic peace cs_secure"
|
|
expire = 14d
|
|
}
|
|
|
|
module { name = "cs_register" }
|
|
module { name = "cs_set" }
|
|
module { name = "cs_access" }
|
|
module { name = "cs_ban" }
|
|
module { name = "cs_kick" }
|
|
module { name = "cs_mode" }
|
|
module { name = "cs_topic" }
|
|
module { name = "cs_info" }
|
|
module { name = "cs_list" }
|
|
module { name = "cs_drop" }
|
|
|
|
module
|
|
{
|
|
name = "operserv"
|
|
client = "OperServ"
|
|
}
|
|
|
|
module { name = "os_akill" }
|
|
module { name = "os_mode" }
|
|
module { name = "os_kick" }
|
|
module { name = "os_kill" }
|
|
module { name = "os_list" }
|
|
module { name = "os_stats" }
|
|
module { name = "os_reload" }
|
|
module { name = "os_shutdown" }
|
|
|
|
module
|
|
{
|
|
name = "botserv"
|
|
client = "BotServ"
|
|
defaults = "dontkickops fantasy greet"
|
|
}
|
|
|
|
module { name = "bs_bot" }
|
|
module { name = "bs_assign" }
|
|
|
|
module
|
|
{
|
|
name = "hostserv"
|
|
client = "HostServ"
|
|
}
|
|
|
|
module { name = "hs_set" }
|
|
module { name = "hs_request" }
|
|
|
|
module
|
|
{
|
|
name = "memoserv"
|
|
client = "MemoServ"
|
|
maxmemos = 20
|
|
}
|
|
|
|
module { name = "ms_send" }
|
|
module { name = "ms_read" }
|
|
module { name = "ms_del" }
|
|
module { name = "ms_list" }
|
|
|
|
module
|
|
{
|
|
name = "global"
|
|
client = "Global"
|
|
}
|
|
|
|
module { name = "gl_global" }
|
|
|
|
opertype
|
|
{
|
|
name = "Services Root"
|
|
commands = "*"
|
|
privs = "*"
|
|
}
|
|
|
|
oper
|
|
{
|
|
name = "bluejay"
|
|
type = "Services Root"
|
|
}
|
|
|
|
module
|
|
{
|
|
name = "db_flatfile"
|
|
database = "anope.db"
|
|
fork = no
|
|
}
|
|
|
|
log
|
|
{
|
|
target = "services.log"
|
|
admin = "*"
|
|
override = "chanserv/* nickserv/* operserv/*"
|
|
commands = "chanserv/* nickserv/* operserv/*"
|
|
servers = "*"
|
|
channels = "*"
|
|
users = "connect disconnect"
|
|
}
|
|
---
|
|
# UnrealIRCd PVC
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: unrealircd-data
|
|
namespace: irc
|
|
spec:
|
|
accessModes: [ReadWriteOnce]
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
---
|
|
# Anope PVC
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: anope-data
|
|
namespace: irc
|
|
spec:
|
|
accessModes: [ReadWriteOnce]
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
---
|
|
# UnrealIRCd Deployment
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: unrealircd
|
|
namespace: irc
|
|
labels:
|
|
app: unrealircd
|
|
spec:
|
|
replicas: 1
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app: unrealircd
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: unrealircd
|
|
spec:
|
|
initContainers:
|
|
- name: inject-credentials
|
|
image: busybox:1.36
|
|
command: ["sh", "-c"]
|
|
args:
|
|
- |
|
|
OPER_PW=$(cat /secrets/password)
|
|
LINK_PW=$(cat /secrets/Link-Password)
|
|
sed -e "s|__OPER_PASSWORD__|${OPER_PW}|g" \
|
|
-e "s|__LINK_PASSWORD__|${LINK_PW}|g" \
|
|
/config-template/unrealircd.conf > /injected-config/unrealircd.conf
|
|
echo "Credentials injected into unrealircd.conf"
|
|
volumeMounts:
|
|
- name: irc-credentials
|
|
mountPath: /secrets
|
|
readOnly: true
|
|
- name: unrealircd-config-template
|
|
mountPath: /config-template
|
|
readOnly: true
|
|
- name: injected-config
|
|
mountPath: /injected-config
|
|
- name: copy-tls
|
|
image: busybox:1.36
|
|
command: ["sh", "-c"]
|
|
args:
|
|
- |
|
|
cp /tls-secret/tls.crt /tls/server.cert.pem
|
|
cp /tls-secret/tls.key /tls/server.key.pem
|
|
chmod 644 /tls/server.cert.pem
|
|
chmod 644 /tls/server.key.pem
|
|
chown 1000:1000 /tls/server.cert.pem /tls/server.key.pem 2>/dev/null || true
|
|
chmod 777 /data
|
|
volumeMounts:
|
|
- name: irc-tls-secret
|
|
mountPath: /tls-secret
|
|
readOnly: true
|
|
- name: irc-tls
|
|
mountPath: /tls
|
|
- name: unrealircd-data
|
|
mountPath: /data
|
|
containers:
|
|
- name: unrealircd
|
|
image: djlegolas/unrealircd:6.1.9.1
|
|
ports:
|
|
- containerPort: 6667
|
|
name: irc-plain
|
|
- containerPort: 6697
|
|
name: irc-tls
|
|
- containerPort: 8067
|
|
name: services-link
|
|
volumeMounts:
|
|
- name: injected-config
|
|
mountPath: /app/conf/unrealircd.conf
|
|
subPath: unrealircd.conf
|
|
- name: unrealircd-config-template
|
|
mountPath: /app/conf/ircd.motd
|
|
subPath: ircd.motd
|
|
readOnly: true
|
|
- name: unrealircd-data
|
|
mountPath: /app/data
|
|
- name: irc-tls
|
|
mountPath: /app/conf/tls
|
|
resources:
|
|
requests:
|
|
memory: 64Mi
|
|
cpu: 50m
|
|
limits:
|
|
memory: 256Mi
|
|
cpu: 250m
|
|
volumes:
|
|
- name: irc-credentials
|
|
secret:
|
|
secretName: irc-credentials
|
|
- name: unrealircd-config-template
|
|
configMap:
|
|
name: unrealircd-config-template
|
|
- name: injected-config
|
|
emptyDir: {}
|
|
- name: unrealircd-data
|
|
persistentVolumeClaim:
|
|
claimName: unrealircd-data
|
|
- name: irc-tls-secret
|
|
secret:
|
|
secretName: irc-tls
|
|
- name: irc-tls
|
|
emptyDir: {}
|
|
---
|
|
# Anope IRC Services Deployment
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: anope
|
|
namespace: irc
|
|
labels:
|
|
app: anope
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: anope
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: anope
|
|
spec:
|
|
initContainers:
|
|
- name: inject-credentials
|
|
image: busybox:1.36
|
|
command: ["sh", "-c"]
|
|
args:
|
|
- |
|
|
LINK_PW=$(cat /secrets/Link-Password)
|
|
sed -e "s|__LINK_PASSWORD__|${LINK_PW}|g" \
|
|
/config-template/services.conf > /injected-config/services.conf
|
|
echo "Credentials injected into services.conf"
|
|
volumeMounts:
|
|
- name: irc-credentials
|
|
mountPath: /secrets
|
|
readOnly: true
|
|
- name: anope-config-template
|
|
mountPath: /config-template
|
|
readOnly: true
|
|
- name: injected-config
|
|
mountPath: /injected-config
|
|
- name: fix-perms
|
|
image: busybox:1.36
|
|
command: ["sh", "-c"]
|
|
args:
|
|
- |
|
|
mkdir -p /data/db /data/logs /data/runtime
|
|
touch /data/anope.db /data/services.motd
|
|
chmod 666 /data/anope.db
|
|
chown -R 10000:10000 /data 2>/dev/null || chmod -R 777 /data
|
|
echo "Anope data dir prepared: $(ls -la /data/anope.db)"
|
|
volumeMounts:
|
|
- name: anope-data
|
|
mountPath: /data
|
|
containers:
|
|
- name: anope
|
|
image: anope/anope:latest
|
|
volumeMounts:
|
|
- name: injected-config
|
|
mountPath: /anope/conf/services.conf
|
|
subPath: services.conf
|
|
- name: anope-data
|
|
mountPath: /anope/data
|
|
resources:
|
|
requests:
|
|
memory: 64Mi
|
|
cpu: 25m
|
|
limits:
|
|
memory: 128Mi
|
|
cpu: 100m
|
|
volumes:
|
|
- name: irc-credentials
|
|
secret:
|
|
secretName: irc-credentials
|
|
- name: anope-config-template
|
|
configMap:
|
|
name: anope-config-template
|
|
- name: injected-config
|
|
emptyDir: {}
|
|
- name: anope-data
|
|
persistentVolumeClaim:
|
|
claimName: anope-data
|
|
---
|
|
# The Lounge web IRC Deployment
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: thelounge
|
|
namespace: irc
|
|
labels:
|
|
app: thelounge
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: thelounge
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: thelounge
|
|
spec:
|
|
initContainers:
|
|
- name: install-flowercore-theme
|
|
image: ghcr.io/thelounge/thelounge:4.4.3
|
|
command:
|
|
- sh
|
|
- -lc
|
|
- |
|
|
set -eu
|
|
THELOUNGE_HOME=/var/opt/thelounge thelounge install file:/flowercore-theme
|
|
volumeMounts:
|
|
- name: thelounge-config
|
|
mountPath: /var/opt/thelounge/config.js
|
|
subPath: config.js
|
|
- name: thelounge-packages
|
|
mountPath: /var/opt/thelounge/packages
|
|
- name: thelounge-flowercore-theme
|
|
mountPath: /flowercore-theme
|
|
containers:
|
|
- name: thelounge
|
|
image: ghcr.io/thelounge/thelounge:4.4.3
|
|
ports:
|
|
- containerPort: 9000
|
|
name: http
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: http
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 10
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /
|
|
port: http
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 20
|
|
resources:
|
|
requests:
|
|
memory: 64Mi
|
|
cpu: 50m
|
|
limits:
|
|
memory: 256Mi
|
|
cpu: 250m
|
|
volumeMounts:
|
|
- name: thelounge-config
|
|
mountPath: /var/opt/thelounge/config.js
|
|
subPath: config.js
|
|
- name: thelounge-packages
|
|
mountPath: /var/opt/thelounge/packages
|
|
volumes:
|
|
- name: thelounge-config
|
|
configMap:
|
|
name: thelounge-config
|
|
- name: thelounge-packages
|
|
emptyDir: {}
|
|
- name: thelounge-flowercore-theme
|
|
configMap:
|
|
name: thelounge-flowercore-theme
|
|
---
|
|
# UnrealIRCd Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: unrealircd
|
|
namespace: irc
|
|
spec:
|
|
selector:
|
|
app: unrealircd
|
|
ports:
|
|
- port: 6667
|
|
targetPort: 6667
|
|
name: irc-plain
|
|
- port: 6697
|
|
targetPort: 6697
|
|
name: irc-tls
|
|
- port: 8067
|
|
targetPort: 8067
|
|
name: services-link
|
|
---
|
|
# Anope Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: anope
|
|
namespace: irc
|
|
spec:
|
|
selector:
|
|
app: anope
|
|
ports:
|
|
- port: 8067
|
|
targetPort: 8067
|
|
name: services-link
|
|
---
|
|
# The Lounge web IRC Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: thelounge
|
|
namespace: irc
|
|
spec:
|
|
selector:
|
|
app: thelounge
|
|
ports:
|
|
- port: 9000
|
|
targetPort: 9000
|
|
name: http
|
|
---
|
|
# Traefik IngressRouteTCP - IRC plain (6667)
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: IngressRouteTCP
|
|
metadata:
|
|
name: irc-plain
|
|
namespace: irc
|
|
spec:
|
|
entryPoints:
|
|
- irc
|
|
routes:
|
|
- match: HostSNI(`*`)
|
|
services:
|
|
- name: unrealircd
|
|
port: 6667
|
|
---
|
|
# Traefik IngressRouteTCP - IRC TLS passthrough (6697)
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: IngressRouteTCP
|
|
metadata:
|
|
name: irc-tls
|
|
namespace: irc
|
|
spec:
|
|
entryPoints:
|
|
- irctls
|
|
routes:
|
|
- match: HostSNI(`*`)
|
|
services:
|
|
- name: unrealircd
|
|
port: 6697
|
|
tls:
|
|
passthrough: true
|
|
---
|
|
# Traefik IngressRoute - The Lounge web IRC
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: webirc
|
|
namespace: irc
|
|
spec:
|
|
entryPoints:
|
|
- websecure
|
|
routes:
|
|
- match: Host(`webirc.iamworkin.lan`)
|
|
kind: Rule
|
|
services:
|
|
- name: thelounge
|
|
port: 9000
|
|
tls:
|
|
secretName: webirc-tls
|