1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
{
povSelf,
config,
lib,
...
}:
let
inherit (lib) types;
cfg = lib.getAttrFromPath povSelf config;
in
{
options = {
enable = {
type = types.bool;
default = false;
};
domain = {
type = types.str;
};
adminUsers = {
type = with types; listOf str;
default = [];
};
};
config = lib.mkIf cfg.enable {
dns.zones."${cfg.domain}" = {
SRV = [
{
proto = "tcp";
service = "xmpp-server";
priority = 0;
weight = 5;
port = 5269;
target = "xmpp.${cfg.domain}.";
}
{
proto = "tcp";
service = "xmpp-client";
priority = 0;
weight = 5;
port = 5222;
target = "xmpp.${cfg.domain}.";
}
];
subdomains = {
"muc.xmpp".SRV = [
{
proto = "tcp";
service = "xmpp-server";
priority = 0;
weight = 5;
port = 5269;
target = "xmpp.${cfg.domain}.";
}
];
"upload.xmpp".CNAME = [ "${config.networking.fqdn}." ];
xmpp.CNAME = [ "${config.networking.fqdn}." ];
};
};
networking.firewall.allowedTCPPorts = [
5269
5222
] ++ config.services.prosody.httpsPorts;
modules.filesystem.impermanence.system.dirs = [
{
directory = config.services.prosody.dataDir;
mode = "755";
user = config.services.prosody.user;
group = config.services.prosody.group;
}
];
security.acme.certs."${cfg.domain}" = {
group = config.services.prosody.group;
reloadServices = [ "prosody.service" ];
extraDomainNames = [
"xmpp.${cfg.domain}"
"muc.xmpp.${cfg.domain}"
"upload.xmpp.${cfg.domain}"
];
};
services.prosody = {
enable = true;
allowRegistration = false;
authentication = "internal_hashed";
admins = cfg.adminUsers;
# c2sRequireEncryption = true;
# s2sSecureAuth = true;
disco_items = [
{
url = "muc.xmpp.${cfg.domain}";
description = "Channels";
}
{
url = "upload.xmpp.${cfg.domain}";
description = "File upload";
}
];
modules = {
disco = true; # Service discovery
roster = true; # Allow users to have a roster. Recommended ;)
saslauth = true; # Authentication for clients and servers. Recommended if you want to log in.
tls = true; # Add support for secure TLS on c2s/s2s connections
blocklist = true; # Allow users to block communications with other users
bookmarks = true; # Synchronise the list of open rooms between clients
carbons = true; # Keep multiple online clients in sync
dialback = true; # Support for verifying remote servers using DNS
limits = true; # Enable bandwidth limiting for XMPP connections
pep = true; # Allow users to store public and private data in their account
private = true; # Private XML storage (for room bookmarks, etc.)
smacks = true; # Allow a client to resume a disconnected session, and prevent message loss
vcard = true; # User profiles (stored in PEP)
vcard_legacy = true; # Conversion between legacy vCard and PEP Avatar, vcard
csi = true; # Allows clients to report their active/inactive state
ping = true; # Replies to XMPP pings with pongs
register = true; # Allow users to register on this server using a client and change passwords
time = true; # Let others know the time here on this server
uptime = true; # Report how long server has been running
version = true; # Replies to server version requests
mam = true; # Store recent messages to allow multi-device synchronization
};
extraModules = [
"admin_adhoc" # Allows administration via an XMPP client that supports ad-hoc commands
"admin_shell" # Allow secure administration via 'prosodyctl shell'
"invites" # Create and manage invites
"invites_adhoc" # Allow admins/users to create invitations via their client
"invites_register" # Allows invited users to create accounts
];
httpsPorts = [ 5281 ];
httpFileShare.domain = "upload.xmpp.${cfg.domain}";
ssl.cert = "${config.security.acme.certs."${cfg.domain}".directory}/fullchain.pem";
ssl.key = "${config.security.acme.certs."${cfg.domain}".directory}/key.pem";
virtualHosts = {
zaphyra = rec {
enabled = true;
domain = "zaphyra.eu";
ssl.cert = "${config.security.acme.certs."${domain}".directory}/fullchain.pem";
ssl.key = "${config.security.acme.certs."${domain}".directory}/key.pem";
};
};
muc = [
{
domain = "muc.xmpp.${cfg.domain}";
name = "zaphyra Chat";
restrictRoomCreation = "local";
extraConfig = ''
modules_enabled = {
"muc_mam";
"muc_archive";
"vcard_muc";
"measure_muc";
"pastebin";
}
'';
}
];
};
};
}