In short, the gpio pins are the same as on the raspberry pi, so the only thing we need to do is add the correct dt overlay and reboot.
# wget https://raw.githubusercontent.com/libre-computer-project/libretech-overlays/for-4.13.y/overlays/meson-gxl-s905x-libretech-cc-uarta.dts
# armbian-add-overlay meson-gxl-s905x-libretech-cc-uarta.dts
# reboot
The uart will now be available at /dev/ttyAML6
# dmesg | grep -i AML
[ 0.000000] Machine model: Libre Computer AML-S905X-CC
[ 0.000000] Kernel command line: root=UUID=cf37c48a-ba15-4e4e-9944-b06c87736116 rootwait rootfstype=ext4 splash=verbose console=ttyAML0,115200 console=tty1 consoleblank=0 coherent_pool=2M loglevel=1 ubootpart=8a0630c8-01 libata.force=noncq usb-storage.quirks= cgroup_enable=memory swapaccount=1
[ 1.328575] soc soc0: Amlogic Meson GXL (S905X) Revision 21:d (84:2) Detected
[ 1.338375] c11084c0.serial: ttyAML6 at MMIO 0xc11084c0 (irq = 18, base_baud = 1500000) is a meson_uart
[ 1.339501] c1108700.serial: ttyAML7 at MMIO 0xc1108700 (irq = 19, base_baud = 1500000) is a meson_uart
[ 1.340352] c81004c0.serial: ttyAML0 at MMIO 0xc81004c0 (irq = 20, base_baud = 1500000) is a meson_uart
And we just tell zigbee2mqtt which device to use in the docker container.
# docker run -d --name zigbee2mqtt --restart=unless-stopped --device=/dev/ttyAML6:/dev/ttyAML6 -p 8092:8080 -v /root/zigbee2mqtt/data:/app/data -v /run/udev:/run/udev:ro -e TZ=Europe/Oslo koenkk/zigbee2mqtt