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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
|
+++
title = "cozy ejabberd xmpp chat server"
created_at = "2023-09-16T21:07:40+0100"
tags = ["tech", "sysadmin"]
+++
today we are going to do the **ultimate** *cozy* ejabberd server guide. the only prerequisites for this guide are, one, having already set up some form of server, whether it be a vps, or an old laptop behind your fridge, it doesn't matter, because this isn't the email network, and two, ownership of a domain name, e.g. `blos.sm`.
we shall begin with a single virtualhost[^1]. for example purposes, we will use `example.slay` (let's imagine this is a real tld because why not) as the domain. just replace all instances of `example.slay` with your own domain.
[^1]: virtualhosts allow more than one xmpp service to be run on one server. for example, you could have one xmpp service with the domain `example.slay` and another xmpp service with the domain `example.flop`, both somewhat separated from each other as if they were run on different servers.
<div>
<div class="panel checklist">
checklist!:
- [ ] add dns records
- [ ] open firewall ports
- [ ] set up web server
- [ ] get ssl certificates
- [ ] set up postgres database
- [ ] install ejabberd
- [ ] write configuration
- [ ] start service
</div>
## step 1: set up your dns records
you will need dns A/AAAA records and srv records for each service on your xmpp server.
you will need a records for:
- `example.slay`
- `muc.example.slay` (for group chats)
- `upload.example.slay` (for http file upload)
- `pubsub.example.slay` (for the pubsub node)
- `proxy.example.slay` (for file transfer proxy)
- `stun.example.slay` (for stun/turn)
each pointing to the ip address of your server that is going to run ejabberd. the last two are technically optional, but i would recommend them.
as well as srv records for each, pointing to a domain that resolves to your server, as so:
(all records are in the form
`_service._proto.name IN SRV priority weight port target`)
```
_xmpp-client._tcp IN SRV 5 0 5222 example.slay.
_xmpps-client._tcp IN SRV 5 0 5223 example.slay.
_xmpp-server._tcp IN SRV 5 0 5269 example.slay.
_xmpps-server._tcp IN SRV 5 0 5270 example.slay.
```
and
```
_xmpp-client._tcp.muc IN SRV 5 0 5222 example.slay.
_xmpps-client._tcp.muc IN SRV 5 0 5223 example.slay.
_xmpp-server._tcp.muc IN SRV 5 0 5269 example.slay.
_xmpps-server._tcp.muc IN SRV 5 0 5270 example.slay.
```
for each of the subdomains (starting with muc). exclude `stun.example.slay`.
you will then have to add one last set of srv records for stun/turn.
```
_stun._udp IN SRV 5 0 3478 stun.example.slay.
_stun._tcp IN SRV 5 0 3478 stun.example.slay.
_stuns._tcp IN SRV 5 0 5349 stun.example.slay.
_turn._udp IN SRV 5 0 3478 stun.example.slay.
_turn._tcp IN SRV 5 0 3478 stun.example.slay.
_turns._tcp IN SRV 5 0 5349 stun.example.slay.
```
extra info: as a result of these records, you could technically play around with hosting xmpp on a server other than the one at `example.slay` (i.e. if you were splitting services across servers on one domain) by using the srv delegation. further info can be found at [XEP-0368](https://xmpp.org/extensions/xep-0368.html).
## step 2: open your firewall ports
open ports:
tcp: `80` `443` `5222` `5223` `5269` `5270` `3478` `5349` `49152-65535`
udp: `3478` `49152-65535`
`80` & `443` are for the web server, `5222`, `5223`, `5269` and `5270` are for xmpp, and the rest are for stun/turn.
## step 3: set up your web server and get your ssl certificates
you need to:
- get (an) ssl certificate(s) for your domain, as well as several subdomains, all in all:
- `example.slay`
- `muc.example.slay`
- `upload.example.slay`
- `pubsub.example.slay`
- `proxy.example.slay`
- `stun.example.slay`
- proxypass http://127.0.0.1:5443 through to:
- https://example.slay/xmpp
- https://example.slay/.well-known/host-meta
- https://example.slay/.well-known/host-meta.json
make sure that for /xmpp you have what is necessary to proxy websockets too. if you're using nginx, increase `client_max_body_size` for http uploads.
- make sure the certificate files are readable and/or in a place that is readable by the `ejabberd` user
you can technically avoid using something like nginx + certbot, and use the built-in [ejabberd acme module](https://docs.ejabberd.im/admin/configuration/basic/#acme), thereby skipping this, but i am assuming you may also want to host other web services on your system, in which case you would want to reverse proxy each http service to a single https web service.
## step 4: set up postgres database
we will be creating a separate database for each virtualhost, as i feel this makes things clearer, and also it easier to migrate individual virtualhosts in the future. however, there is also now the ability to only have one, as described [here](https://docs.ejabberd.im/admin/configuration/database/#default-and-new-schemas).
you should follow standard postgresql installation instructions for your OS. at the time of writing, the database driver for ejabberd does [not support](https://github.com/processone/p1_pgsql/issues/6) `scram-sha-256`, so you will need to [set](https://www.postgresql.org/docs/16/runtime-config-connection.html#GUC-PASSWORD-ENCRYPTION) `password_encryption = 'md5'` in your `postgresql.conf` file.
once this has been done, you should connect to your database as an admin and:
1. create an ejabberd database user with `CREATE USER ejabberd WITH PASSWORD 'your_password';`. don't forget to change the password.
2. create a database for your virtualhost with `CREATE DATABASE ejabberd_example OWNER ejabberd;`. replace `example` with something corresponding to your virtualhost.
3. import the database schema from github with the command `su -c "curl -s https://raw.githubusercontent.com/processone/ejabberd/master/sql/pg.sql | psql ejabberd_example" ejabberd` (once again replace `example`).
note down the postgres ejabberd user password.
## step 5: install ejabberd
now you should finally install the [system package](https://docs.ejabberd.im/admin/installation/#operating-system-packages). make sure that your build has postgresql support.
make sure that the file `/etc/ejabberd/ejabberd.yml` exists, and of course, is readable by the user that runs ejabberd (almost definitely `ejabberd`), by, if necessary, copying over the example `ejabberd.yml` or `wget`/`curl`ing it from the [github repo](https://github.com/processone/ejabberd/blob/master/ejabberd.yml.example). if you are getting it from the repo, make sure the version corresponds to the version of ejabberd packaged by your os.
## step 6: ejabberd configuration
- loglevel last
- create docroot for uploads
begin by replacing `localhost` under `hosts` with your virtualhost (e.g. `example.slay`), then list the certfiles you have obtained under `certfiles`.
now set `default_db: sql` at the root level of the yaml file. this should be followed by `host_config` and the database configuration for your virtualhost, as shown below. customise each value to your setup.
```
host_config:
example.slay:
sql_type: pgsql
sql_server: "localhost"
sql_port: 5432
sql_username: "ejabberd"
sql_password: "postgres_password"
sql_database: "ejabberd_example"
auth_method: sql
auth_password_format: scram
```
under `listen`, ensure all the correct services are enabled on each port, including tls s2s on port `5270` (not default):
```
listen:
-
port: 5222
module: ejabberd_c2s
max_stanza_size: 262144
shaper: c2s_shaper
access: c2s
starttls_required: true
-
port: 5223
tls: true
module: ejabberd_c2s
max_stanza_size: 262144
shaper: c2s_shaper
access: c2s
starttls_required: true
-
port: 5269
module: ejabberd_s2s_in
max_stanza_size: 524288
-
port: 5270
tls: true
module: ejabberd_s2s_in
max_stanza_size: 524288
```
we will also be enabling the http server and the stun/turn server modules. make sure you have set `turn_ipv4_address` and `ip` to your server's ipv4 address.
```
-
port: 5443
module: ejabberd_http
request_handlers:
/xmpp/admin: ejabberd_web_admin
/xmpp/bosh: mod_bosh
/xmpp/upload: mod_http_upload
/xmpp/ws: ejabberd_http_ws
/.well-known/host-meta: mod_host_meta
/.well-known/host-meta.json: mod_host_meta
-
port: 3478
transport: udp
module: ejabberd_stun
use_turn: true
turn_min_port: 49152
turn_max_port: 65535
# The server's public IPv4 address:
turn_ipv4_address: 0.0.0.0
-
port: 5349
transport: tcp
module: ejabberd_stun
use_turn: true
tls: true
turn_min_port: 49152
turn_max_port: 65535
ip: 0.0.0.0
turn_ipv4_address: 0.0.0.0
```
now set `s2s_use_starttls: required` at the root.
at this point you can set up some ACLs. `acls` are just the access control lists, you can also set up `access_rules` corresponding to your needs, which will be what are passed to module settings. example:
```
acl:
admin:
user: admin@example.slay
flop:
- user: flop@example.slay
clown:
- user: clown@example.slay
access_rules:
queens:
allow: flop
allow: clown
```
next, we will be adding some modules under `modules` and changing some settings.
add abuse addresses under `mod_disco`:
```
modules:
# ...
mod_disco:
server_info:
-
modules: all
name: "abuse-addresses"
urls: ["mailto:abuse@example.slay"]
```
add `mod_host_meta`:
```
mod_host_meta:
bosh_service_url: "https://@HOST@/xmpp/bosh"
websocket_url: "wss://@HOST@/xmpp/ws"
```
edit `mod_mam`, and change `assume_mam_usage` to `false` and `default` to `never` if you wish not to archive messages on the server:
```
mod_mam:
db_type: sql
assume_mam_usage: never
default: never
```
add `mod_stun_disco` to advertise the stun service to clients, changing `0.0.0.0` and `example.slay` to your server's ip and hostname respectively:
```
mod_stun_disco:
credentials_lifetime: 12h
services:
-
host: 0.0.0.0
port: 3478
type: stun
transport: udp
restricted: false
-
host: 0.0.0.0
port: 3478
type: turn
transport: udp
restricted: true
-
host: stun.example.slay
port: 5349
type: stuns
transport: tcp
restricted: false
-
host: stun.example.slay
port: 5349
type: turns
transport: tcp
restricted: true
```
now it is time to enable MUCs (multi-user chatrooms), file proxy, http upload, and pubsub.
### mucs:
make sure that you set the host to your muc subdomain, otherwise it will attempt to use `conference.example.slay`. you can also set `mam: false` in `default_room_options` to disable server-side message archiving by default.
```
mod_muc:
host: muc.example.slay
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
access_mam:
- allow
default_room_options:
mam: false
```
### file proxy:
```
mod_proxy65:
access: local
max_connections: 5
```
### http file upload:
```
mod_http_upload:
put_url: https://@HOST@/xmpp/upload
docroot: /var/www/ejabberdupload
max_size: 1073741824
custom_headers:
"Access-Control-Allow-Origin": "https://@HOST@"
"Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
"Access-Control-Allow-Headers": "Content-Type"
```
create the folder for the `docroot`, and make sure it is owned by the `ejabberd` user.
### pubsub:
```
mod_pubsub:
access_createnode: pubsub_createnode
plugins:
- flat
- pep
force_node_config:
## Avoid buggy clients to make their bookmarks public
storage:bookmarks:
access_model: whitelist
```
## step 7:
start the ejabberd server! once you are done and believe everything has been set up correctly, you can optionally change the [`loglevel`](https://docs.ejabberd.im/admin/configuration/toplevel/#loglevel) at the root of the config.
</div>
<hr>
# extra goodies!
## further virtualhosts?
for further virtualhosts you should create a new database for each, and add them to the database part of the config. e.g.:
```
host_config:
example.slay:
sql_type: pgsql
sql_server: "localhost"
sql_port: 5432
sql_username: "ejabberd"
sql_password: "postgres_password"
sql_database: "ejabberd_slay"
auth_method: sql
auth_password_format: scram
example.flop:
sql_type: pgsql
sql_server: "localhost"
sql_port: 5432
sql_username: "ejabberd"
sql_password: "postgres_password"
sql_database: "ejabberd_flop"
auth_method: sql
auth_password_format: scram
```
there cannot be conflicts between declarations in the config file, so if you have `mod_muc`, `mod_proxy65`, `mod_http_upload` and `mod_pubsub` declared under `modules` at the root, they (as well as other configuration differences between virtualhosts) must be deleted and replicated for each virtualhost under `append_host_config` at the root. example as so:
```
append_host_config:
example.flop:
modules:
mod_muc:
host: muc.example.flop
access_create: flops
access_persistent: flops
access:
- allow
access_admin:
- allow: admin
default_room_options:
mam: false
mod_proxy65:
access: flops
max_connections: 5
mod_http_upload:
access: flops
put_url: https://@HOST@/xmpp/upload
docroot: /var/www/ejabberdupload
max_size: 1073741824
custom_headers:
"Access-Control-Allow-Origin": "https://@HOST@"
"Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
"Access-Control-Allow-Headers": "Content-Type"
mod_pubsub:
access_createnode: flops
plugins:
- flat
- pep
force_node_config:
## Avoid buggy clients to make their bookmarks public
storage:bookmarks:
access_model: whitelist
example.flop:
modules:
mod_muc:
hosts:
- muc.example.flop
access_create: local
access_persistent: local
access:
- allow
access_admin:
- allow: admin
default_room_options:
mam: false
mod_proxy65:
access: local
max_connections: 5
mod_http_upload:
put_url: https://@HOST@/xmpp/upload
docroot: /var/www/ejabberdupload
max_size: 1073741824
custom_headers:
"Access-Control-Allow-Origin": "https://@HOST@"
"Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
"Access-Control-Allow-Headers": "Content-Type"
mod_pubsub:
access_createnode: pubsub_createnode
plugins:
- flat
- pep
force_node_config:
## Avoid buggy clients to make their bookmarks public
storage:bookmarks:
access_model: whitelist
```
as you can see above, you may also want to disable access to certain services per virtualhost using ACLs, in order to e.g. prevent users on `example.slay` from creating MUCs on `muc.example.flop`.
|