# !/bin/bash # Rocket.Chat Matrix Federation Setup # Author: Alan Sikora # https://github.com/alansikora PWD=$(pwd) [[ $1 = "-dev" ]] && DEV=true || DEV=false # Set image versions ROCKETCHAT_IMAGE_TAG="5.4.0" SYNAPSE_IMAGE_TAG="v1.71.0" TRAEFIK_IMAGE_TAG="v2.9.4" REDIS_IMAGE_TAG="6.2.7" NGINX_IMAGE_TAG="1.23.2" ELEMENT_IMAGE_TAG="v1.11.14" # Set config RC_BRIDGE_PORT=3300 updateEnvFile () { echo "" > .env cat << EOF > .env # Rocket.Chat CLI RC_IMAGE=$RC_IMAGE ROCKETCHAT_IMAGE_TAG=$ROCKETCHAT_IMAGE_TAG SYNAPSE_IMAGE_TAG=$SYNAPSE_IMAGE_TAG TRAEFIK_IMAGE_TAG=$TRAEFIK_IMAGE_TAG REDIS_IMAGE_TAG=$REDIS_IMAGE_TAG NGINX_IMAGE_TAG=$NGINX_IMAGE_TAG ELEMENT_IMAGE_TAG=$ELEMENT_IMAGE_TAG # Setup SERVER_HOSTNAME=$SERVER_HOSTNAME RC_BRIDGE_PORT=$RC_BRIDGE_PORT # Let's Encrypt LETSENCRYPT_EMAIL=$LETSENCRYPT_EMAIL # Matrix AS_UNIQUE_ID=$AS_UNIQUE_ID AS_HS_TOKEN=$AS_HS_TOKEN AS_AS_TOKEN=$AS_AS_TOKEN EOF } alpineImageOrNot () { read -p "Do you with to use the alpine version (y/n) [n]: " if [ "$REPLY" = "y" ]; then RC_IMAGE="$RC_IMAGE-alpine" fi; } imageLatestStable () { RC_IMAGE="rocket.chat:$ROCKETCHAT_IMAGE_TAG" if [ $DEV = true ]; then alpineImageOrNot fi } echo "" echo "Rocket.Chat Matrix Federation Setup" if [ $DEV = true ]; then echo ">>>>>>>> DEV MODE ENABLED <<<<<<<<<" fi echo "" # Check if docker is installed DOCKER_INFO=$(docker info &> /dev/null) RESULT=$? if [ $RESULT -ne 0 ]; then if [ $RESULT -eq 127 ]; then echo "Please, install the latest docker version then run this script again:" echo "https://docs.docker.com/engine/install/" echo "" exit 1 else echo "Looks like you might have docker installed, but the wrong permissions, try this:" echo "" echo "> sudo groupadd docker" echo "> sudo usermod -aG docker $USER" echo "> newgrp docker" echo "" echo "And run this command again." echo "" exit 1 fi fi # Import env vars if [ -f "$PWD/.env" ]; then printf "Loading env vars...\n" export $(grep -v '^#' .env | xargs) echo "" fi # Generate application service data if [ -z "$AS_UNIQUE_ID" ]; then CURRENT=$(date +%s) AS_UNIQUE_ID=${AS_UNIQUE_ID:=$(echo "unique_$CURRENT" | sha1sum | head -c 40)} AS_HS_TOKEN=${AS_HS_TOKEN:=$(echo "hs_$CURRENT" | sha256sum | head -c 64)} AS_AS_TOKEN=${AS_AS_TOKEN:=$(echo "as_$CURRENT" | sha256sum | head -c 64)} fi if [ -z "$SERVER_HOSTNAME" ]; then read -p "Type your server's hostname (without https or trailing slashes): " SERVER_HOSTNAME="$REPLY" updateEnvFile printf "\nPlease, create the following records pointing to your server's IP address:\n" printf " - $SERVER_HOSTNAME\n" printf " - synapse.$SERVER_HOSTNAME\n" printf " - element.$SERVER_HOSTNAME\n" printf " - traefik.$SERVER_HOSTNAME\n" printf "\n" fi if [ -z "$LETSENCRYPT_EMAIL" ]; then read -p "Type your email address, will be used to issue certificates: " LETSENCRYPT_EMAIL="$REPLY" updateEnvFile printf "\n" fi if [ $DEV = true ]; then printf "Which Rocket.Chat image you want to use? (current: "; if [ -z "${RC_IMAGE}" ]; then printf "none" else printf "$RC_IMAGE" fi printf ")\n" RC_IMAGE_DEFAULT_OPTION=1 if ! [ -z "${RC_IMAGE}" ]; then printf "0) keep current\n" RC_IMAGE_DEFAULT_OPTION=0 fi; printf "1) latest stable\n" printf "2) latest dev\n" printf "3) specific version\n" printf "4) specific PR\n" read -p "Pick an option [$RC_IMAGE_DEFAULT_OPTION]: " case $REPLY in 1) imageLatestStable ;; 2) RC_IMAGE="rocket.chat:develop" ROCKETCHAT_IMAGE_TAG="develop" alpineImageOrNot ;; 3) read -p "Type the version: " RC_IMAGE="rocket.chat:$REPLY" ROCKETCHAT_IMAGE_TAG="$REPLY" ;; 4) read -p "Type the PR number: " RC_IMAGE="ghcr.io/rocketchat/rocket.chat:pr-$REPLY" ROCKETCHAT_IMAGE_TAG="pr-$REPLY" ;; *) if [ "$RC_IMAGE_DEFAULT_OPTION" = 1 ]; then imageLatestStable fi esac echo "" else imageLatestStable fi updateEnvFile # Setup synapse printf "Setting up Synapse...\n" mkdir -p data/matrix/synapse if [ ! -f "$PWD/data/matrix/synapse/homeserver.yaml" ]; then docker run -it --rm \ -v $(pwd)/data/matrix/synapse:/data \ -e SYNAPSE_SERVER_NAME="$SERVER_HOSTNAME" \ -e SYNAPSE_REPORT_STATS=yes \ -e UID=1000 \ -e GID=1000 \ matrixdotorg/synapse:$SYNAPSE_IMAGE_TAG generate fi if ! grep -q "enable_registration: true" data/matrix/synapse/homeserver.yaml; then sed -i '$ d' data/matrix/synapse/homeserver.yaml tee -a data/matrix/synapse/homeserver.yaml > /dev/null < /dev/null < data/matrix/nginx/matrix.conf tee -a data/matrix/nginx/matrix.conf > /dev/null < data/traefik/acme.json chmod 0600 data/traefik/acme.json fi # - Setup config: middlewares tee data/traefik/config/middlewares.yml > /dev/null <<'EOF' http: middlewares: httpsredirect: redirectScheme: scheme: https permanent: true EOF # - Setup config: routers tee data/traefik/config/routers.yml > /dev/null <<'EOF' http: routers: redirecttohttps: entryPoints: - "web" middlewares: - "httpsredirect" rule: "HostRegexp(`{host:.+}`)" service: "noop@internal" EOF # - Setup traefik.yml tee data/traefik/traefik.yml > /dev/null < /dev/null < /dev/null <<'EOF' services: traefik: image: "traefik:${TRAEFIK_IMAGE_TAG}" restart: "unless-stopped" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./data/traefik/traefik.yml:/etc/traefik/traefik.yml:ro" - "./data/traefik/config:/config:ro" - "./data/traefik/acme.json:/acme.json" labels: - "traefik.enable=true" - "traefik.http.services.traefik.loadbalancer.server.port=8080" - "traefik.http.routers.traefik.rule=Host(`traefik.$SERVER_HOSTNAME`)" - "traefik.http.routers.traefik.entrypoints=web-secure" - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" networks: - internal postgres: image: "postgres:14" restart: "unless-stopped" environment: POSTGRES_PASSWORD: itsasecret POSTGRES_USER: synapse POSTGRES_DB: synapse POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'" volumes: - "./data/postgres/data:/var/lib/postgresql/data" networks: - internal redis: image: "redis:${REDIS_IMAGE_TAG}" restart: "unless-stopped" networks: - internal synapse: image: "matrixdotorg/synapse:${SYNAPSE_IMAGE_TAG}" restart: "unless-stopped" environment: SYNAPSE_CONFIG_DIR: "/data" SYNAPSE_CONFIG_PATH: "/data/homeserver.yaml" UID: "1000" GID: "1000" TZ: "America/New_York" volumes: - "./data/matrix/synapse:/data" ports: - 8008:8008 - 8448:8448 labels: - "traefik.enable=true" - "traefik.http.services.synapse.loadbalancer.server.port=8008" - "traefik.http.routers.synapse.rule=Host(`synapse.$SERVER_HOSTNAME`)" - "traefik.http.routers.synapse.entrypoints=web-secure" - "traefik.http.routers.synapse.tls=true" - "traefik.http.routers.synapse.tls.certresolver=letsencrypt" networks: - internal nginx: image: "nginx:${NGINX_IMAGE_TAG}" restart: "unless-stopped" volumes: - "./data/matrix/nginx/matrix.conf:/etc/nginx/conf.d/matrix.conf" labels: - "traefik.enable=true" - "traefik.http.services.nginx.loadbalancer.server.port=80" - "traefik.http.routers.nginx.rule=Host(`$SERVER_HOSTNAME`)" - "traefik.http.routers.nginx.entrypoints=web-secure" - "traefik.http.routers.nginx.tls=true" - "traefik.http.routers.nginx.tls.certresolver=letsencrypt" networks: - internal element: image: vectorim/element-web:${ELEMENT_IMAGE_TAG} restart: unless-stopped volumes: - ./data/element/config.json:/app/config.json labels: - "traefik.enable=true" - "traefik.http.services.element.loadbalancer.server.port=80" - "traefik.http.routers.element.rule=Host(`element.$SERVER_HOSTNAME`)" - "traefik.http.routers.element.entrypoints=web-secure" - "traefik.http.routers.element.tls=true" - "traefik.http.routers.element.tls.certresolver=letsencrypt" networks: - internal rocketchat: image: "${RC_IMAGE}" command: > bash -c "for i in `seq 1 30`; do node main.js && s=$$? && break || s=$$?; echo \"Tried $$i times. Waiting 5 secs...\"; sleep 5; done; (exit $$s)" restart: unless-stopped volumes: - ./uploads:/app/uploads - ./data/matrix/synapse/registration.yaml:/app/matrix-federation-config/registration.yaml environment: - PORT=3000 - ROOT_URL=https://localhost:3000 - MONGO_URL=mongodb://mongodb:27017/rocketchat?replicaSet=rs0&directConnection=true - MONGO_OPLOG_URL=mongodb://mongodb:27017/local?replicaSet=rs0&directConnection=true - NODE_ENV=production # - REG_TOKEN=${REG_TOKEN} depends_on: - mongodb ports: - 3000:3000 - 3300:3300 networks: - internal # labels: # - "traefik.enable=true" # - "traefik.http.services.rc.loadbalancer.server.port=3000" # - "traefik.http.routers.rc.rule=Host(`$SERVER_HOSTNAME`)" # - "traefik.http.routers.rc.entrypoints=web-secure" # - "traefik.http.routers.rc.tls=true" # - "traefik.http.routers.rc.tls.certresolver=letsencrypt" # - "traefik.http.services.bridge.loadbalancer.server.port=$RC_BRIDGE_PORT" # - "traefik.http.routers.bridge.rule=Host(`$SERVER_HOSTNAME`)" # - "traefik.http.routers.bridge.entrypoints=web-secure" # - "traefik.http.routers.bridge.tls=true" # - "traefik.http.routers.bridge.tls.certresolver=letsencrypt" mongodb: image: mongo:5.0 restart: unless-stopped volumes: - ./data/mongo/db:/data/db command: mongod --oplogSize 128 --replSet rs0 labels: - "traefik.enable=false" networks: - internal # this container's job is just run the command to initialize the replica set. # it will run the command and remove himself (it will not stay running) mongo-init-replica: image: mongo:5.0 command: > bash -c "for i in `seq 1 30`; do mongo mongodb/rocketchat --eval \" rs.initiate({ _id: 'rs0', members: [ { _id: 0, host: 'localhost:27017' } ]})\" && s=$$? && break || s=$$?; echo \"Tried $$i times. Waiting 5 secs...\"; sleep 5; done; (exit $$s)" depends_on: - mongodb networks: - internal networks: internal: attachable: true EOF