# 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", 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: | bluejay-bg.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" 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