In recent versions of Tigase XMPP Server (starting with version 8.0) it is possible to create and use multiple username and password pairs to authorize connection to the single XMPP account.
With that in place, it is now possible to have multiple passwords for multiple clients accessing the same account that can be used to increase security of the account. Even if one of the passwords is compromised, you can still log in and block a lost or compromised device.
To add a new username-password pair, you need to execute Add user credentials ad-hoc command (command node auth-credentials-add at sess-man) while logged in the XMPP account for which you want to add a new application password.
During execution of a command, you will be provided with a form to fill in with following fields:
jid) - bare JID of your accountcredentialId) - username for the new application passwordpassword) - a new password<iq type='set' to='[email protected]' id='sasl-app-add-1'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-add' action='execute'/>
</iq>
<iq type='result' from='[email protected]' id='sasl-app-add-1' to='[email protected]/resource-1'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-add' session-id='uuid-xxxxxx' status='executing'>
<x xmlns='jabber:x:data' type='form'>
<title>Add user credentials"</title>
<field var='jid' label='The Jabber ID for the account' type='jid-single'/>
<field var='credentialId' label='Credential ID' type='jid-single'/>
<field var='password' label='Password' type='text-single'/>
</x>
</command>
</iq>
After submitting this form a new credential will be added.
<iq type='set' to='[email protected]' id='sasl-app-add-2'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-add' action='execute'>
<x xmlns='jabber:x:data' type='submit'>
<title>Add user credentials"</title>
<field var='jid' label='The Jabber ID for the account' type='jid-single'>
<value>[email protected]</value>
</field>
<field var='credentialId' label='Credential ID' type='jid-single'>
<value>my-new-app-1</value>
</field>
<field var='password' label='Password' type='text-single'>
<value>39jfnwu053743</value>
</field>
</x>
</command>
</iq>
<iq type='result' from='[email protected]' id='sasl-app-add-2' to='[email protected]/resource-1'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-add' session-id='uuid-xxxxxx' status='completed'>
<x xmlns='jabber:x:data' type='result'>
<field type='fixed'>
<value>OK</value>
</field>
</x>
</command>
</iq>
To log in with new password the XMPP client can use any SASL mechanism, but it needs to provide (in the SASL message):
authzid - account JIDauthcid - username for application passwordpasswd - application passwordWith proper values, you application will be able to log in using application password.
In case of SASL PLAIN which has the following format (spaces should be ommited and [] means it is optional):
[authzid] UTF8NUL authcid UTF8NUL passwd
not encoded payload would look like this:
[email protected] UTF8NUL my-new-app-1 UTF8NUL 39jfnwu053743
That after Base64 encoding would be presented as dXNlckBleGFtcGxlLmNvbQBteS1uZXctYXBwLTEDOWpmbnd1MDUzNzQz and this value can be used as a correct CData of <auth/> element:
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>dXNlckBleGFtcGxlLmNvbQBteS1uZXctYXBwLTEDOWpmbnd1MDUzNzQz</auth>
If your device is compromised or lost and you want to remove the application password, you need to use a different device and log in on your XMPP account.
Then you need to execute Delete user credentials ad-hoc command (command node auth-credentials-delete at sess-man).
During execution for a command you will be provided with a form to fill in with following fields:
jid) - bare JID of your accountcredentialId) - username for the application password which you want to remove<iq type='set' to='[email protected]' id='sasl-app-delete-1'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-delete' action='execute'/>
</iq>
<iq type='result' from='[email protected]' id='sasl-app-delete-1' to='[email protected]/resource-1'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-delete' session-id='uuid-xxxxxx' status='executing'>
<x xmlns='jabber:x:data' type='form'>
<title>Add user credentials"</title>
<field var='jid' label='The Jabber ID for the account' type='jid-single'/>
<field var='credentialId' label='Credential ID' type='jid-single'/>
</x>
</command>
</iq>
After submitting this form a credential will be removed.
<iq type='set' to='[email protected]' id='sasl-app-delete-2'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-delete' action='execute'>
<x xmlns='jabber:x:data' type='submit'>
<title>Add user credentials"</title>
<field var='jid' label='The Jabber ID for the account' type='jid-single'>
<value>[email protected]</value>
</field>
<field var='credentialId' label='Credential ID' type='jid-single'>
<value>my-new-app-1</value>
</field>
</x>
</command>
</iq>
<iq type='result' from='[email protected]' id='sasl-app-delete-2' to='[email protected]/resource-1'>
<command xmlns='http://jabber.org/protocol/commands' node='auth-credentials-delete' session-id='uuid-xxxxxx' status='completed'>
<x xmlns='jabber:x:data' type='result'>
<field type='fixed'>
<value>OK</value>
</field>
</x>
</command>
</iq>
NOTE: This version requires JDK17!
NOTE: Complete list of changes available in
tigase-server-8.4.0milestone
away (tigase/_server/server-core#1527)<build/> element in XEP-0092: Software Version (tigase/_server/server-core#1522)ecdsa (tigase/_server/tigase-utils#28)Docker is a very convenient abstraction layer that allows ease and consistency of deployment of software. However, it requires that the image platform matches the platform on which we want to run the software. Luckily, docker has multi-platform support which allows to both run images from different platform and, via buildx, create images for variety of platforms. There is a small downside to it - it uses QEMU to, as name may suggest, emulate other platforms, which entails one downside - performance penalty, both when running the image as well as when creating it.
During recent preparation of Tigase XMPP Server 8.3 release I faced an issue where, due to introduction of jlink into our build pipeline to make the images smaller and more lean, additional processing made creation of multi-platform images virtually impossible.
Fortunately, buildx tool is very versatile an allows using multiple builders to create images and in addition, those builders can be remote so it’s possible to take advantage of computing instances from cloud providers to build images for platforms not native to the machine on which we run the build making the build speed native-like.

There is nothing all that special when it comes to remote machine preparation - it has to have docker installed (follow Install on Linux guide or one dedicated to partiular distribution used). One caveat is to make sure that it’s possible to use docker without sudo which is easily accheved by adding user to docker group:
$sudo gpasswd -a $USER docker
(restart of the shell session required afterwards).
Machine has to be accessible via ssh. Another caveat - because it’s not possible to specify key used it has to either be one available via SSH Agent or one of the following files: id_rsa, id_ed25519, id_ecdsa, id_dsa or identity under ~/.ssh.
After everything is set up it’s possible to check if everything is correct byt executing info command:
docker -H ssh://<usernane>@<hostname> info
which should give output similar to the one below:
Client:
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc., v0.9.1)
compose: Docker Compose (Docker Inc., v2.12.2)
dev: Docker Dev Environments (Docker Inc., v0.0.3)
extension: Manages Docker extensions (Docker Inc., v0.2.13)
sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc., 0.6.0)
scan: Docker Scan (Docker Inc., v0.21.0)
Server:
Containers: 2
Running: 1
Paused: 0
Stopped: 1
Images: 2
Server Version: 20.10.22
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 78f51771157abb6c9ed224c22013cdf09962315d
runc version: v1.1.4-0-g5fd4c4d
init version: de40ad0
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 5.11.0-1022-aws
Operating System: Ubuntu 20.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.901GiB
Name: ip-172-31-48-98
ID: X6BF:XU3T:QUBB:M5NY:IGEV:UAQL:6PJ5:GTGO:EBDX:73AS:UD5X:IY5A
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
buildxThe catch here is to create a builder that has two nodes: one local for one architecture and then another one for another architecture.
Let’s add new local builder for arm64 platform (I’m running the build on MacBook with M1 chipset):
docker buildx create --node local --name local-remote-builder --driver docker-container --platform linux/arm64
Checking available builders with docker buildx ls should give following output
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
local-remote-builder docker-container
local unix:///var/run/docker.sock inactive linux/arm64*
Let’s add remote machine to builds for x86 architecture. The caveat is to use --append parameter to add remote node to just created builder:
docker buildx create --append --name local-remote-builder --node remote --driver docker-container --platform linux/amd64 ssh://<usernane>@<hostname>
Available nodes at this time should include our remote builder:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
local-remote-builder docker-container
local unix:///var/run/docker.sock inactive linux/arm64*
remote ssh://<usernane>@<hostname> inactive linux/amd64*
Builders are still inactive so it’s essential to make sure they are properly booted before execution with
docker buildx inspect --bootstrap --builder local-remote-builder
command, yielding following ouput if everything went correctly
[+] Building 12.2s (2/2) FINISHED
=> [local internal] booting buildkit 2.9s
=> => pulling image moby/buildkit:buildx-stable-1 2.3s
=> => creating container buildx_buildkit_local 0.5s
=> [remote internal] booting buildkit 7.7s
=> => pulling image moby/buildkit:buildx-stable-1 1.1s
=> => creating container buildx_buildkit_remote 6.4s
Name: local-remote-builder
Driver: docker-container
Nodes:
Name: local
Endpoint: unix:///var/run/docker.sock
Status: running
Buildkit: v0.10.5
Platforms: linux/arm64*, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
Name: remote
Endpoint: ssh://<usernane>@<hostname>
Status: running
Buildkit: v0.10.5
Platforms: linux/amd64*, linux/amd64/v2, linux/amd64/v3, linux/386
The only remaining thing is to set newly created and configured builder to be used by default via
docker buildx use local-remote-builder
and with that our builder list should look like this (nodes listed as running and builder annotated with asterisk indicating it’s the default one):
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
local-remote-builder * docker-container
local unix:///var/run/docker.sock running v0.10.5 linux/arm64*, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
remote ssh://<usernane>@<hostname> running v0.10.5 linux/amd64*, linux/amd64/v2, linux/amd64/v3, linux/386
With everything in place, building latest version of Tigase XMPP Server 8.3 is a matter of executing buildx build command with desired target platforms:
docker buildx build --platform linux/amd64,linux/arm64 -t tigase/tigase-xmpp-server:${VERSION} -f ${VERSION}/Dockerfile --no-cache ${VERSION}/
giving us image in less than a minute.
]]>You can download both application from their respective app-stores: Beagle IM from macOS appstore and Siskin IM from iOS appstore and star them on GitHub: Siskin IM on GitHub and Beagle IM on GitHub
You can discuss all-things-Tigase (including our client apps) on our groupchat: [email protected]

keygen tool instead of using sun.* API unavailable under JDK17SCRAM-*-PLUS SASL mechanisms [#server-1335]'urn:xmpp:bind:0' and 'urn:xmpp:sasl:2' in 'sess-man' [#server-1332]socket-buffer-size property (please see socket-buffer-size documentation).<r/> requests, #server-1324 (#150)socket-buffer-size option to ConnectionManager to configure SO_RCVBUF separately from internal network buffers, #server-1325socket-buffer-size for client-to-server and inter-cluster connections and added documentation, #server-1325MAX_PAUSE property name; #server-1326SCRAM-*-PLUS SASL mechanisms; #server-1335lastXmppPacketReceivedTime member to avoid WatchDog closing connection before lastXmppPacketReceivedTime is set; #server-1337'from' set; #server-1338The stable release of BeagleIM 4.1 contains a lot of changes and stability improvements.
alt when sharing image file)





The stable release of SiskinIM 6.1 contains changes and stability improvements.
You can download both application from their respective app-stores: Beagle IM from macOS appstore and Siskin IM from iOS appstore and star them on GitHub: Siskin IM on GitHub and Beagle IM on GitHub
You can discuss all-things-Tigase (including our client apps) on our groupchat: [email protected]

Communication with your family and friends is not only about instant chats. Audio and Video calls are quite important and sometimes, under unfavourable network configurations establishing a call may prove difficult. Luckily, with the help of STUN (Session Traversal Utilities for NAT) and TURN (Traversal Using Relays around NAT ) servers it’s no longer a problem
In the following guide we will show how to setup TURN and STUN servers with Tigase XMPP Server, so that compatible XMPP clients will be able to use them. Our xmpp.cloud installation supports not only them, but also XMPP MIX
We are assuming that you have installed your preferred TURN server and created an account on the TURN server for use by your XMPP server users and that you have installed and configured Tigase XMPP Server.
At the end of the article there is a short guide how to quickly setup CoTURN server.
NOTE: It is required only for Tigase XMPP Server 8.1.0 and earlier
First you need to edit etc/config.tdsl file and:
'ext-disco' () {}
sess-man section of the file:
'urn:xmpp:extdisco:2' () {}
so that your config file would look like this:
'ext-disco' () {}
'sess-man' () {
'urn:xmpp:extdisco:2' () {}
}
After applying changes mentioned above, you need to start Tigase XMPP Server or, in case if it was running, restart it.
Open web browser and head to http://<your-xmpp-server-and-port>/admin/ (for example: https://localhost:8080). When promped, log in by providing admin user credentials: bare JID (i.e.: user@domain) as the user and related password. Afterwards you’ll see main Web AdminUI screen:

and on that screen open Configuration group on the left by clicking on it.
After opening Configuration group (1) click on Add New Item (2) position which has ext-disco@… in its subtitle.
In the opened form you need to provide following detail:

[email protected])TURN server)turn.example.com)3478)turnudp or tcp (usually udp but item can be added for both)turn-user)turn-password)After filling out the form, press Submit button (3) to send form and add a TURN server to external services for your server. Admin UI will confirm that service was added with the following result

While adding a TURN server is usually all what you need, in some cases you may want to allow your users to use also STUN. Steps are quite similar like on TURN server - after opening Configuration group (1) click on Add New Item (2) position which has ext-disco@… in its subtitle and in the opened form you need to provide following detail:

[email protected])STUN server)stun.example.com)3478)stunudp or tcp (usually udp but item can be added for both)If you are using the same server for STUN and TURN (you usually will as TURN servers usually contain STUN functionality) you will fill the following form with almost the same details *(only use different Service field value, Type will be stun and most likely you will skip passing Username and Password - leaving them empty, the rest of the field values will be the same).
After filling out the form, press Submit button (3) to send form and add a STUN server to external services for your server. Admin UI will confirm that service was added with the following result

Now you have fully configured your STUN/TURN server for usage with Tigase XMPP Server allowing XMPP clients connected to your server and compatible with XEP-0215: External Service Discovery to take full advantage of your STUN/TURN server ie. by providing better VoIP experience.
You can quickly setup CoTURN server using Docker. Please follow Docker installation on your operating system and then install CoTURN using Docker Hub (instrumentisto/coturn). The bare minimum required to run it looks like that (please update realm with your domain and external-ip with IP on which server should be accessible):
sudo docker run \
--name coturn \
-p 3478:3478 \
-p 3478:3478/udp \
-p 5349:5349 \
-p 5349:5349/udp \
-p 49160-49200:49160-49200 \
coturn/coturn \
--log-file=stdout \
--min-port=49160 \
--max-port=49200 \
--realm localhost \
--user tigase:tigase \
--lt-cred-mech \
--fingerprint \
--external-ip=$$(detect-external-ip)
NOTE: It uses
tigaseas username/password andlocalhostas realm - please adjust if needed
Alternatively, you can use Docker Compose to quickly spin up complete Tigase XMPP Server with CoTURN configured - see our Docker Compose guide for details.
]]><complete/> attributeMIX / group chat creation streamlined

Better VoIP connectivity

Message Correction, Retraction and quick replies

<iq/> requests which should fix some OMEMO key publication issues.Fixed an issue with encrypting files with AESGCM send to MUC rooms when default encryption is set to OMEMO (#siskinim-237)

You can download both application from their respective app-stores: Beagle IM from macOS appstore and Siskin IM from iOS appstore and star them on GitHub: Siskin IM on GitHub and Beagle IM on GitHub
You can discuss all-things-Tigase (including our client apps) on our groupchat: [email protected]

Some time ago, we started developing multiplatform XMPP Library called Halcyon based on Kotlin Multiplatform by Jetbrains. Our plan is to allow using the same library in different target environments: JVM, Android, JavaScript and Native. Currently we are focused on JVM and JavaScript targets.
In this post we will try to show library design and example of usage.

Because Halcyon isn’t published in any Maven repository (yet), you need to compile it yourself. We believe, it will not be a problem. The only two things you need to do is to clone repository and compile library:
```shell script git clone https://github.com/tigase/halcyon.git cd halcyon ./gradlew publishToMavenLocal
Thats all. Now Halcyon is in your local Maven repository.
## Let's do something
We recommend using Gradle to build everything (except for towers and bridges maybe). You can also use Maven, it doesn't matter. Just use one of them, to prevent problems with dependencies.
Here is sample `build.gradle.kts` file, the most important this is to enable kotlin plugin and include Hayclon in the list of dependencies:
```kotlin
plugins {
java
kotlin("jvm") version "1.3.61"
}
repositories {
mavenLocal()
jcenter()
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("tigase.halcyon:halcyon-core-jvm:0.0.1")
testCompile("junit", "junit", "4.12")
}
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
Let’s add some Kotlin code:
fun main(args: Array<String>) {
val client = Halcyon()
client.configure {
userJID = "[email protected]".toBareJID()
password = "secret"
}
client.connectAndWait()
client.disconnect()
}
This simple code creates XMPP client, connects to XMPP server and then disconnects.
To show how to work with Halcyon library, we will by adding code to this small code base.
Halcyon is events-driven library. It means, that each part of library may publish event to event bus and all registered listeners will receive it.
Lets add some code to see what is being send and received over XMPP stream:
client.eventBus.register<ReceivedXMLElementEvent>(ReceivedXMLElementEvent.TYPE) { event ->
println(">> ${event.element.getAsString()}")
}
client.eventBus.register<SentXMLElementEvent>(SentXMLElementEvent.TYPE) { event ->
println("<< ${event.element.getAsString()}")
}
To listen for all events since the connection is started, we have to add this code before client.connectAndWait().
All events extend class tigase.halcyon.core.eventbus.Event, so you can easily find them all in your favourite IDE.
Each module may have it’s own set of events, so please check documentation or source code of modules of interest.
Now we will look at one of the most interesting things in XMPP: requests and responses.
XMPP protocol allows sending request to another entity and receive response. Why is it so exciting? Because we can ping other clients, or ask for their local time! Ok, stop joking. Of course above examples are true, but with request-response we can do much more than simple sending messages: we can manage our contacts list, we can manage Multi User Chatrooms, we can execute remote methods on server or other clients.
As an example we will ping other XMPP entity (it may be server or other client).
First we need to get PingModule to be able to use its request builder:
val pingModule = client.getModule<PingModule>(PingModule.TYPE)!!
Ping module has method ping() which creates a request builder (note, that it doesn’t send anything yet!) configured to understand response and return it as object.
Method ping() has optional parameter jid. If is not provided, then ping will be send to the server to which the client is connected.
val request = pingModule.ping()
request.response { result ->
when (result) {
is IQResult.Success -> println("Pong in ${result.get()!!.time} ms")
is IQResult.Error -> println("Oops! Error ${result.error}")
}
}
request.send()
There is also a different way to add response handler to the request:
request.handle {
success { request, iq, result -> println("Pong in ${result!!.time} ms") }
error { request, iq, errorCondition, message -> println("Oops! Error $errorCondition") }
}
Use the one that you prefer.
One more example: we will check list of features of our server:
val discoveryModule = client.getModule<DiscoveryModule>(DiscoveryModule.TYPE)!!
discoveryModule.info("sampleserver.org".toJID()).handle {
error { request, iq, errorCondition, message -> println("Oops! Error $errorCondition") }
success { request, iq, result ->
println("Server JID: ${result!!.jid}")
println("Features:")
result!!.features.forEach { println(" - $it") }
}
}.send()
This chapter will be very hard, mostly because MessageModule isn’t finished yet.
We haven’t made a design decision yet - how this module should work. It is good for you though, because we can create message stanza from scratch! And it’s cool!
This is how message stanza look like:
<message
from='[email protected]/balcony'
id='ktx72v49'
to='[email protected]'>
<body>Art thou not Romeo, and a Montague?</body>
</message>
Let’s try to create this stanza in Kotlin and send it.
var messageRequest = client.request.message {
to = "[email protected]".toJID()
body = "Art thou not Romeo, and a Montague?"
}
messageRequest.send()
The only thing currently implemented in MessageModule is MessageReceivedEvent, useful to handle all incoming message stanzas:
client.eventBus.register<MessageReceivedEvent>(MessageReceivedEvent.TYPE) { event ->
println("Message from ${event.fromJID}: ${event.stanza.body}")
}
Ok, we can send a message to anybody, but most of the time we want to send them to our friends. We need a list of our friends. Luckily such list is available out-of-box in XMPP protocol: it is called Roster.
It shouldn’t be a surprise, but to manage your roster you need RosterModule:
var rosterModule = client.getModule<RosterModule>(RosterModule.TYPE)!!
We can add (or update, with the same method) roster items, remove and list them.
val allRosterItems = rosterModule.store.getAllItems()
RosterItem contains JabberID of the contact, list of groups being assigned to, status of subscription (if contact is allowed to see our presence or not, and if we are allowed to see it’s presence).
Presence is “status of contact”. You can see if your contacts are online, offline or maybe you shouldn’t send any message to someone because he has “Do Not Disturb” status.
As an example, we will list all contacts from the roster and their presence:
rosterModule.store.getAllItems().forEach { rosterItem ->
val presenceStanza = presenceModule.getBestPresenceOf(rosterItem.jid)
println("${rosterItem.name} <${rosterItem.jid}> : ${presenceStanza?.show ?: "Offline"}")
}
…for being here up to this point. We hope you enjoyed reading about Halcyon library, and you liked it even though it is not finished yet.
Please share you thoughts and ideas at our group chat [email protected] or on library GitHub page.
]]>Running Tigase XMPP Server was never easier - you can have a full-fledged XMPP server in a matter of minutes.
Using containers offers various benefits - it helps bundle complete execution environment that’s consistent, isolates various services and orchestrates them with ease. This makes setting up new service a breeze. At the same time Docker is only a thin layer with very little performance overhead. In Tigase’s case, even though normally only JVM is required, having single bundle with recommended version of the JVM and configured environment helps achieve the most compatible and stable setup.
If you haven’t already, install Docker engine on your desired operating system. Once this is done, starting Tigase is just two commands away (for up-to-date list of tags check out our DockerHub, by default latest is used):
$ docker pull tigase/tigase-xmpp-server
$ docker run --name tigase-server -p 8080:8080 -p 5222:5222 tigase/tigase-xmpp-server
And after a short Tigase will start and you’ll be presented with option to setup the server by accessing http://localhost:8080 page. Once setup is completed, simply restart the container with $ docker restart tigase-server and connect your client.

Of course above is the simplest deployment. There are many possibilities to adjust the container by mounting local volumes, exposing more ports or connecting to external database. It’s even possible to run local Tigase cluster! For details please check out Tigase in Docker guide
Our images are based on Java 11, which already supports Docker without any issues.
]]>