automated-setup/script/MANUAL_SETUP.md

32 KiB

Manual Setup Guide

This document contains detailed manual configuration instructions for LetsBe infrastructure components.

Note: Most of these steps are handled automatically by the deployment scripts. This guide is for manual intervention, troubleshooting, and advanced configuration.


Table of Contents


Updating Any App With Docker Compose

docker compose down && docker compose pull && docker image prune -f && docker compose up -d

Public Key

Before running the start.sh script ensure the file "id_ed25519.key" is in the same path as the README.md here or add / decrypt. Always keep the file "id_ed25519.key" secure as you can access all server with all permissions with it.

Domain DNS Entries

Preset subdomains can be adjusted before executing the start.sh script under "env_setup.sh" part: "# Start - Set subdomain per tool". Note that you cannot use the same domain name more than once, each tool must have its own subdomain name.

Each subdomain must then be added as an "A" DNS record in the domain settings, with the Server IP that you receive after purchasing a new server for the target customer.

You should create the "A" DNS entries before starting the "start.sh" script and then wait at least 15 minutes before you go on.

Redash First Installation

Make sure to uncomment ports in docker-compose.

Required Subdomains (A Records)

Set up these A records before running the installation script. All should point to your server's IP address.

Core Subdomains

  1. {root} - Main domain (e.g., client.com)
  2. www - Standard www prefix

Tools & Applications

  1. activepieces - Workflow automation (automation.client.com)
  2. baserow - Database management (database.client.com)
  3. calcom - Appointment scheduling (bookings.client.com)
  4. chatwoot - Customer support (support.client.com)
  5. collabora - Document collaboration (collabora.client.com)
  6. documenso - Document signing (documenso.client.com)
  7. ghost - Content management/blogging (blog.client.com)
  8. gitea - Code repository (code.client.com)
  9. glitchtip - Error tracking (debug.client.com)
  10. html - Static website hosting (html.client.com)
  11. keycloak - Authentication service (auth.client.com)
  12. librechat - AI chat service (chat.client.com)
  13. listmonk - Email newsletter service (newsletters.client.com)
  14. nextcloud - File storage/collaboration (cloud.client.com)
  15. nocodb - Low-code database (crm.client.com)
  16. odoo - Business management (erp.client.com)
  17. penpot - Design platform (design.client.com)
  18. portainer - Container management (containers.client.com)
  19. poste - Email server (mail.client.com)
  20. redash - Data visualization (data.client.com)
  21. squidex - Headless CMS (contenthub.client.com)
  22. stirlingpdf - PDF manipulation (pdf.client.com)
  23. typebot - Conversational forms (botlab.client.com and bots.client.com)
  24. umami - Analytics (analytics.client.com)
  25. uptime-kuma - Monitoring (uptime.client.com)
  26. whiteboard - Collaborative whiteboarding (whiteboard.client.com)
  27. windmill - Workflow automation (flows.client.com)
  28. wordpress - Website/blog (www.client.com or client.com)

Infrastructure Subdomains

  1. minio - Object storage admin interface (minio.client.com)
  2. s3 - S3-compatible storage endpoint (s3.client.com)
  3. n8n - Workflow automation alternative (n8n.client.com)
  4. ci - Continuous integration (for Gitea/Drone) (ci.client.com)
  5. marketing - Optional marketing site (marketing.client.com)
  6. helpdesk - Help desk/documentation (helpdesk.client.com)

After Installation

All tools must be prepared and the administrator account must be created/changed. This must be done immediately after installation:

* = No Embedding for External Apps

Tool Setup Required
baserow Admin account must be created via the website
*calcom Admin account must be created via the website
*chatwoot Need to be changed (probably default: Username: "john@acme.inc", Password: "Password1!")
gitea Admin account must be created via the website
glitchtip Admin account must be created via the website under register new account
listmonk Admin account details auto generated and can be found in initial_setup_backup.zip: stacks/listmonk/config.toml
*n8n Admin account must be created via the website
nextcloud Admin account details auto generated and can be found in initial_setup_backup.zip: stacks/nextcloud/docker-compose.yml under "app" & "environment"
nextcloud collabora Admin account details auto generated and can be found in initial_setup_backup.zip: stacks/nextcloud/docker-compose.yml under "collabora" & "environment"
*odoo Admin account must be created via the website
penpot Admin account must be created via the website under register new account
*poste Admin account must be created via the website
*squidex Admin account must be created via the website under register new account
*umami Need to be changed (default: Username: "admin", Password: "umami")
*uptime-kuma Admin account must be created via the website
windmill Need to be changed (default: E-Mail: "admin@windmill.dev", Password: "changeme")
*wordpress Admin account must be created via the website

Additional Notes:

  • Add typebot subdomains: botlab & bots
  • Restart REDIS container for activepieces after installation!
  • UNCOMMENT MINIO SSL/HPARAM LINES IN NGINX AFTER SETUP!!

Calcom Setup Post-Ansible

  1. Go to env and generate a new calendso encryption using: openssl rand -base64 24
  2. Add NEXT_PUBLIC_API_V2_URL=https://bookings.{domain}

Docker-Compose and Nginx Config Location

  • Docker compose: /opt/letsbe/stacks/AppName
  • Nginx: /etc/nginx/sites-available

E-Mails DNS Settings Example

A, mail.mydomain.com
MX, Name: @ Value: mail.mydomain.com (Priority: 10)
TXT, Name: _dmarc.mydomain.com Value: v=DMARC1; p=none; rua=mailto:administrator@mydomain.com
TXT, Name: @ Value: v=spf1 mx ~all
TXT = DKIM Name & Value: (generate for root domain in poste)

IF DNS MANAGEMENT IS WIX:

TXT, Name: domain.com Value: v=spf1 mx a:mail.qluxurymedia.com a:support.qluxurymedia.com ~all

Email Ports:

  • IMAP without SSL (unencrypted): 143
  • IMAP with SSL (encrypted): 993
  • SSL/TLS Outgoing: 465

IMPORTANT: You MUST request another certificate in the TLS settings for Poste in order for IMAP to work!


For Containers

  • 127.0.0.1 = local
  • 0.0.0.0 = network wide

Clients with Existing Email Inboxes

  1. Run setup of server, ensure client inserts mail.domain.com A level record first (Only setup A level until after sync, then when you're ready to launch you do the rest), and that the SSL certificate is pulled and valid
  2. Setup Poste mailserver
  3. Ask client to change password on original mail server account (for their protection)
  4. IMAP sync (Use internal container IP if hostnames are the same for the destination):
    imapsync --host1 oldmailserver.com --user1 olduser --password1 oldpassword \
             --host2 newmailserver.com --user2 newuser --password2 newpassword
    
  5. Once synced, change existing DNS records and create new ones and delete existing conflicting ones - MX records are vital here, do NOT change them until the new server is ready for use

Collabora URL Example for Nextcloud

https://admin:password@collabora.mydomain.com

Tool-Specific Setup

Whiteboard

DO NOT install whiteboard before setting it up properly

If mimetypealiases not found:

docker exec -u 33 -it customer-nextcloud-app php /var/www/html/occ maintenance:mimetype:update-db
docker exec -u 33 -it customer-nextcloud-app php /var/www/html/occ maintenance:mimetype:update-js

Setup Steps:

  1. Setup docker-compose and nginx if you haven't already made them standard
  2. Generate JWT token: openssl rand -base64 32
  3. Set that token for nextcloud and in the docker compose for the whiteboard:
    docker exec -u 33 -it {CUSTOMER}-nextcloud-app php /var/www/html/occ config:app:set whiteboard jwt_secret_key --value="your-random-key"
    
  4. Make NGINX config and link with:
    sudo ln -s /etc/nginx/sites-available/whiteboard.conf /etc/nginx/sites-enabled/
    
  5. Generate SSL
  6. Restart nginx and reload docker compose

Known Issues: If the integration_whiteboard app was previously installed there might be a leftover non-standard mimetype configured. In this case opening the whiteboard may fail and a file is downloaded instead. Make sure to remove any entry in config/mimetypealiases.json mentioning whiteboard and run:

docker exec -u 33 -it customer-nextcloud-app php /var/www/html/occ maintenance:mimetype:update-js -vvv
docker exec -u 33 -it customer-nextcloud-app php /var/www/html/occ maintenance:mimetype:update-db -vvv

Finding Certificates with Certbot

sudo certbot certificates

Example (portnimara):

sudo certbot --nginx --expand -d portnimara.com -d www.portnimara.com \
-d analytics.portnimara.com \
-d automation.portnimara.com \
-d cloud.portnimara.com \
-d code.portnimara.com \
-d collabora.portnimara.com \
-d contenthub.portnimara.com \
-d crm.portnimara.com \
-d database.portnimara.com \
-d debug.portnimara.com \
-d design.portnimara.com \
-d flows.portnimara.com \
-d helpdesk.portnimara.com \
-d html.portnimara.com \
-d listmail.portnimara.com \
-d mail.portnimara.com \
-d marketing.portnimara.com \
-d schedule.portnimara.com \
-d support.portnimara.com \
-d uptime.portnimara.com \
-d whiteboard.portnimara.com

IMPORTANT: DO NOT REQUEST CERTIFICATES BEFORE DOING THE LN COMMAND TO CONNECT SITES-AVAILABLE AND SITES-ENABLED


Upgrade Nextcloud over Docker Exec

Find docker-compose files:

sudo find / -name "docker-compose.yml"

Docker composes are found in /opt/letsbe/stacks/AppName

sudo docker exec --user www-data exampleCustomer-nextcloud-app php occ upgrade
docker exec -u www-data -it exampleCustomer-nextcloud-app php occ db:add-missing-indices
# (CHANGE IMAGE IN DOCKER COMPOSE FILE)
docker-compose pull && docker-compose up -d

Best Practice:

sudo docker compose down && sudo docker compose pull && sudo docker compose up -d && sudo docker compose logs -f {customer}-nextcloud-app

If stuck in maintenance mode:

sudo docker exec --user www-data {customer}-nextcloud-app php occ maintenance:mode --off

Remove old images:

docker image prune -f

THEN - do the docker exec commands listed above (occ upgrade and add missing indices)

Nextcloud Webhook Listeners

occ app:enable webhook_listeners

Setting Up WordPress Site on Root Domain

Go to sites-available in the /etc/nginx/sites-available directory and edit the wordpress.conf:

sudo nano wordpress.conf

Add new server block to point to root domain:

# Redirect HTTP to HTTPS for pitzone.io and www.pitzone.io
server {
    listen 80;
    server_name {domain}.{suffix} www.{domain}.{suffix};

    # Redirect all HTTP requests to HTTPS
    return 301 https://$host$request_uri;
}

# HTTPS configuration for pitzone.io with Proxy to Dockerized WordPress
server {
    listen 443 ssl http2;
    server_name {domain} www.{domain};

    # SSL certificate paths from Let's Encrypt
    ssl_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{domain}/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # Proxy requests to the Dockerized WordPress ({customer-wordpress} container)
    location / {
        proxy_pass http://{container_ip}:80;  # Proxy to the Docker container's internal web server
        # TO FIND: sudo docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' {customer}-wordpress
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Deny access to .htaccess files, if any
    location ~ /\.ht {
        deny all;
    }

    # ACME challenge for SSL certificate renewal
    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

Then request certificates with certbot:

sudo certbot --nginx -d {domain} -d www.{domain}

Nginx Errors:

sudo tail -f /var/log/nginx/error.log

Check for auto renewal of certificates:

sudo certbot renew --dry-run

Baserow Setup

  1. Go back into docker-compose after initial setup and mailserver setup
  2. Update email settings to enable automated emails

Example environment configuration:

environment:
  - BASEROW_PUBLIC_URL=https://database.qluxurymedia.com
  - DATABASE_URL=postgresql://bzcdowdmi7:xKaDO81KzhRu7yZ4KWjO@baserow-db:5432/baserow
  - EMAIL_SMTP=True
  - EMAIL_SMTP_USE_TLS=True
  - EMAIL_SMTP_HOST=mail.qluxurymedia.com
  - EMAIL_SMTP_PORT=587
  - FROM_EMAIL=system@qluxurymedia.com
  - EMAIL_SMTP_USER=system@qluxurymedia.com
  - EMAIL_SMTP_PASSWORD=

Chatwoot Setup

For all passwords, use only letters and numbers here

  1. Setup the mail server and create a "support@[domain]" email address, also ensure minio is an A record
  2. Change the .env file to include the password for the support email (you have to set this up when you setup the mail address). The .env file can be found in /opt/letsbe/stacks/chatwoot
  3. Change the .env file to allow users to setup accounts (set to true), set mailer_inbound_email_domain to top level domain (letsbe.biz, for example)
  4. Enter the container using:
    docker exec -it [customername]-chatwoot-rails sh
    
  5. Run each of these:
    bundle exec rails db:setup
    bundle exec rails db:migrate
    
  6. Restart container (MUST BE DONE IN THE DIRECTORY OF THE DOCKER COMPOSE FILE):
    docker-compose down && docker-compose up -d
    
  7. Install and configure getmail6 and MinIO for S3 storage

Updating Chatwoot

docker compose down && docker compose pull && docker image prune -f && docker compose up -d
docker compose run --rm rails bundle exec rails db:chatwoot_prepare

MinIO

  1. Edit docker compose for chatwoot to include MinIO (right above "networks" at the bottom), generate MinIO Root User & Root Password:
minio:
  image: quay.io/minio/minio:RELEASE.2024-10-29T16-01-48Z
  container_name: {client}-minio
  restart: always
  volumes:
    - {client}-minio-data:/data
  environment:
    - MINIO_ROOT_USER={minioadminUsername}
    - MINIO_ROOT_PASSWORD={minioAdminPassword}
  command: server /data --console-address ":9001"
  ports:
    - "127.0.0.1:9000:9000"
    - "127.0.0.1:9001:9001"
  networks:
    matt-chatwoot:
      ipv4_address: 172.20.1.6

createbuckets:
  image: minio/mc
  depends_on:
    - minio
  entrypoint: >
    /bin/sh -c "
    sleep 10;
    mc alias set minio http://minio:9000 {MinIO Admin User} {MinIO Admin Password};
    mc mb minio/typebot;
    mc anonymous set public minio/typebot/public;
    echo '{ \"Version\": \"2012-10-17\", \"Statement\": [{ \"Sid\": \"PublicRead\", \"Effect\": \"Allow\", \"Principal\": \"*\", \"Action\": [\"s3:GetBucketLocation\", \"s3:ListBucket\", \"s3:GetObject\"], \"Resource\": [\"arn:aws:s3:::typebot\", \"arn:aws:s3:::typebot/*\"], \"Condition\": {} }] }' > /tmp/policy.json
    mc admin policy add minio public-read /tmp/policy.json;
    mc admin policy set minio public-read user=minioadmin;
    echo '{ \"CORSRules\": [{ \"AllowedHeaders\": [\"*\"], \"AllowedMethods\": [\"PUT\", \"POST\", \"GET\"], \"AllowedOrigins\": [\"*\"], \"ExposeHeaders\": [\"ETag\"] }] }' > /tmp/cors.json;
    mc cors set minio/typebot /tmp/cors.json;
    exit 0;
    "    
  networks:
    {chatwoot network name}:

And add to "Volumes" at the bottom:

{client}-minio-data:
  1. Edit .env file:
ENABLE_ACCOUNT_SIGNUP=true
SMTP_PASSWORD=
SMTP_PORT=587
MAILER_INBOUND_EMAIL_DOMAIN=[customer_domain]  # letsbe.solutions
RAILS_INBOUND_EMAIL_PASSWORD=[SET]  # set this password, you'll need it for getmail6

# Storage
ACTIVE_STORAGE_SERVICE=s3_compatible
STORAGE_BUCKET_NAME=chatwoot
STORAGE_ACCESS_KEY_ID=[minioRootUser]
STORAGE_SECRET_ACCESS_KEY=[minioRootPassword]
STORAGE_REGION=eu-central
STORAGE_ENDPOINT=https://minio.[domain.com]
STORAGE_FORCE_PATH_STYLE=true

# Amazon S3
S3_BUCKET_NAME=chatwoot
AWS_ACCESS_KEY_ID=[minioRootUser]
AWS_SECRET_ACCESS_KEY=[minioRootPassword]
AWS_REGION=eu-central
AWS_ENDPOINT=https://minio.[domain.com]
AWS_FORCE_PATH_STYLE=true
  1. Go to /etc/nginx/sites-available and make a new minio.conf file (see Nginx Configuration Examples below)

  2. Make s3.conf for the s3 subdomain (see Nginx Configuration Examples below)

  3. DO THIS AFTER YOU REQUEST THE CERTS:

    sudo ln -s /etc/nginx/sites-available/minio.conf /etc/nginx/sites-enabled/
    sudo ln -s /etc/nginx/sites-available/s3.conf /etc/nginx/sites-enabled/
    
  4. Request certificate, restart nginx:

    certbot certificates
    sudo certbot --expand -d analytics.qluxurymedia.com,automation.qluxurymedia.com,...,minio.qluxurymedia.com,s3.qluxurymedia.com
    
  5. Chatwoot .env changes:

    • Set RAILS_INBOUND_EMAIL_SERVICE=relay
    • Add MinIO config
    • Set RAILS_INBOUND_EMAIL_PASSWORD to something secure (to use in the configuration for getmail6)
    • Change storage from "local" - add the MINIO configs

Example .env:

MAILER_SENDER_EMAIL=LetsBe <support@letsbe.solutions>
SMTP_DOMAIN=mail.letsbe.solutions
SMTP_ADDRESS=mail.letsbe.solutions
SMTP_PORT=465
SMTP_USERNAME=support@letsbe.solutions
SMTP_PASSWORD=3eA0GmDttFISUJ9qA0xb94YQz4N9tHObvDq5oBeX7BHg3OK42
SMTP_AUTHENTICATION=login
SMTP_ENABLE_STARTTLS_AUTO=true
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_TLS=true
SMTP_SSL=

MAILER_INBOUND_EMAIL_DOMAIN=letsbe.solutions
RAILS_INBOUND_EMAIL_SERVICE=relay
RAILS_INBOUND_EMAIL_PASSWORD=hDZn9KAHlGFDxeyh1z3o67H3971oh4yfmWDTJR9DrTn9dozwu

ACTIVE_STORAGE_SERVICE=s3_compatible
STORAGE_BUCKET_NAME=chatwoot
STORAGE_ACCESS_KEY_ID=minioadmin
STORAGE_SECRET_ACCESS_KEY=MfHt6x7H9rbfORhkfy9O51OXjFxsC4QHJcobKbs14CMvXJ820
STORAGE_REGION=eu-central
STORAGE_ENDPOINT=https://s3.[domain].com
STORAGE_FORCE_PATH_STYLE=true
  1. Access MinIO Interface and use the root user and password to login

  2. Create a bucket called "chatwoot"

  3. Check .env variables in the customer-chatwoot-rails container (OPTIONAL):

    docker exec -it {customer}-chatwoot-rails sh
    env | grep -E 'AWS|ACTIVE_STORAGE|STORAGE'
    exit
    

Setting up Getmail6

  1. Install getmail6 on the server:

    sudo apt-get update
    sudo apt-get install -y python3-pip
    cd /
    git clone https://github.com/getmail6/getmail6.git
    cd getmail6
    sudo python3 setup.py install
    getmail --version
    
  2. Create a dedicated getmailuser user, and SWITCH TO THAT USER:

    sudo adduser getmailuser
    sudo su - getmailuser
    
  3. Create necessary directories:

    mkdir -p ~/.getmail
    mkdir -p ~/bin
    mkdir -p ~/logs
    
  4. Make sure your RAILS_INBOUND_EMAIL_PASSWORD (Ingress Password) set in the chatwoot .env file is ready

  5. Create the import email script (1 per account, ingress password remains the same):

    nano ~/bin/import_mail_to_chatwoot.sh
    

    Content:

    #!/bin/bash
    INGRESS_PASSWORD="{insert RAILS_INBOUND_EMAIL_PASSWORD here}"
    URL='http://0.0.0.0:3011/rails/action_mailbox/relay/inbound_emails'
    
    curl -sS -u "actionmailbox:{insert RAILS_INBOUND_EMAIL_PASSWORD here}" \
     -A "Action Mailbox: curl relayer" \
     -H "Content-Type: message/rfc822" \
     --data-binary @- \
     $URL
    
  6. Make the script executable:

    chmod +x ~/bin/import_mail_to_chatwoot.sh
    
  7. Create the getmailrc config file (1 per email channel):

    nano ~/.getmail/getmailrc
    

    Content:

    [retriever1]
    type = MultidropIMAPSSLRetriever
    server = mail.letsbe.solutions
    username = support@letsbe.solutions
    password = 3eA0GmDttFISUJ9qA0xb94YQz4N9tHObvDq5oBeX7BHg3OK42
    mailboxes = ("INBOX",)
    envelope_recipient = delivered-to:1
    
    [retriever2]  # Add if you have more mailboxes
    type = MultidropIMAPSSLRetriever
    server = mail.{domain}
    username = help@{domain}
    password = {Password}
    mailboxes = ("INBOX",)
    envelope_recipient = delivered-to:1
    
    [destination]
    type = MDA_external
    path = /home/getmailuser/bin/import_mail_to_chatwoot.sh
    
    [options]
    verbose = 1
    allow_root_commands = true
    read_all = false
    delete = false
    delivered_to = false
    received = false
    message_log = ~/.getmail/getmail.log
    message_log_syslog = false
    message_log_verbose = true
    
  8. Make config executable:

    chmod +x ~/.getmail/getmailrc
    
  9. Test Getmail manually:

    getmail --rcfile ~/.getmail/getmailrc --verbose
    
  10. Setup cron job:

    crontab -e
    

    Add at the bottom:

    */1 * * * * /usr/local/bin/getmail --rcfile /home/getmailuser/.getmail/* --quiet
    
  11. Use "exit" to exit the getmailuser

  12. Setup IMAP settings in Chatwoot App (in channel settings)

  13. Do not forward emails to the address provided by Chatwoot in the channel setup


Nextcloud Context Chat

See: https://docs.nextcloud.com/server/latest/admin_manual/ai/app_context_chat.html#ai-app-context-chat


Apps Only for Tech Savvy People

  1. gitea
  2. Squidex
  3. Windmill

Typebot Installation

Make sure to enact relevant changes in Nginx/Docker compose for s3 and Minio respectively

  1. Create directory:

    mkdir {client-typebot} in /opt/letsbe/stacks/
    
  2. Create docker-compose.yml:

    version: '3.3'
    
    volumes:
      {client}-typebot-db-data:
    
    services:
      {client}-typebot-db:
        image: postgres:16
        restart: always
        volumes:
          - {client}-typebot-db-data:/var/lib/postgresql/data
        environment:
          - POSTGRES_DB=typebot
          - POSTGRES_PASSWORD=typebot
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U postgres"]
          interval: 5s
          timeout: 5s
          retries: 5
        networks:
          {chatwoot_network_name}:
            ipv4_address: 172.20.1.7
    
      typebot-builder:
        image: baptistearno/typebot-builder:latest
        restart: always
        depends_on:
          {client}-typebot-db:
            condition: service_healthy
        ports:
          - '9080:3000'
        extra_hosts:
          - 'host.docker.internal:host-gateway'
        env_file: /opt/letsbe/env/typebot.env
        networks:
          {chatwoot_network_name}:
            ipv4_address: 172.20.1.8
    
      typebot-viewer:
        image: baptistearno/typebot-viewer:latest
        depends_on:
          {client}-typebot-db:
            condition: service_healthy
        restart: always
        ports:
          - '9081:3000'
        env_file: /opt/letsbe/env/typebot.env
        networks:
          {chatwoot_network_name}:
            ipv4_address: 172.20.1.9
    
    networks:
      {chatwoot_network_name}:
        external: true
    
  3. Create typebot.env in /opt/letsbe/env/:

    Generate 64-bit key:

    openssl rand -base64 24 | tr -d '\n' ; echo
    

    Content:

    ENCRYPTION_SECRET={key}
    DATABASE_URL=postgresql://postgres:typebot@typebot-db:5432/typebot
    NODE_OPTIONS=--no-node-snapshot
    NEXTAUTH_URL=https://botlab.letsbe.solutions
    NEXT_PUBLIC_VIEWER_URL=https://bots.letsbe.solutions
    DEFAULT_WORKSPACE_PLAN=UNLIMITED
    ADMIN_EMAIL=administrator@letsbe.solutions
    
    # SMTP Configuration
    SMTP_USERNAME=noreply@letsbe.biz
    SMTP_PASSWORD=NF5joaQH2Q
    SMTP_HOST=mail.letsbe.solutions
    SMTP_PORT=465
    SMTP_SECURE=true
    NEXT_PUBLIC_SMTP_FROM="Typebot Notifications <noreply@letsbe.biz>"
    SMTP_AUTH_DISABLED=false
    
    # S3 Configuration for MinIO
    S3_ACCESS_KEY=minioadmin
    S3_SECRET_KEY=A7wRC52q5BofIjnQFdOaM7aBScS6H7jY54u0aax4P1KCsceP5
    S3_BUCKET=typebot
    S3_PORT=
    S3_ENDPOINT=s3.letsbe.solutions
    S3_SSL=true
    S3_REGION=eu-central
    S3_PUBLIC_CUSTOM_DOMAIN=https://s3.letsbe.solutions
    
  4. Create nginx configs for botlab and bots (see Nginx Configuration Examples below)

  5. Requesting the certs:

    # Link sites-available to sites-enabled first
    sudo certbot --nginx -d botlab.{client}.{domain} -d bots.{client}.{domain}
    sudo nginx -t
    sudo systemctl reload nginx
    

Nginx Configuration Examples

Whiteboard Config

server {
    if ($host = whiteboard.letsbe.solutions) {
        return 301 https://$host$request_uri;
    }

    client_max_body_size 64M;
    listen 80;
    server_name whiteboard.letsbe.solutions;

    location / {
        return 301 https://$host$request_uri;
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

server {
    client_max_body_size 64M;
    listen 443 ssl http2;
    server_name whiteboard.letsbe.solutions;

    ssl_certificate /etc/letsencrypt/live/whiteboard.letsbe.solutions/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/whiteboard.letsbe.solutions/privkey.pem;

    location / {
        proxy_pass http://0.0.0.0:4014;
        proxy_http_version 1.1;
        proxy_read_timeout 3600s;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        add_header X-Frontend-Host $host;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

MinIO Config

server {
    if ($host = minio.letsbe.solutions) {
        return 301 https://$host$request_uri;
    }

    client_max_body_size 64M;
    listen 80;
    server_name minio.letsbe.solutions;

    location / {
        return 301 https://$host$request_uri;
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

server {
    listen 443 ssl http2;
    server_name minio.letsbe.solutions;

    location / {
        proxy_pass http://0.0.0.0:9001;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded_Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }

    ssl_certificate /etc/letsencrypt/live/support.letsbe.solutions/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/support.letsbe.solutions/privkey.pem;
}

S3 Config

server {
    if ($host = s3.qluxurymedia.com) {
        return 301 https://$host$request_uri;
    }

    client_max_body_size 0;
    listen 80;
    server_name s3.qluxurymedia.com;

    location / {
        return 301 https://$host$request_uri;
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

server {
    client_max_body_size 0;
    listen 443 ssl http2;
    server_name s3.qluxurymedia.com;

    ssl_certificate /etc/letsencrypt/live/analytics.qluxurymedia.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/analytics.qluxurymedia.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_hide_header Access-Control-Allow-Origin;

        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' '*' always;
        add_header 'Access-Control-Expose-Headers' 'Origin, Content-Type, Content-MD5, Content-Disposition, ETag' always;

        if ($request_method = 'OPTIONS') {
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            return 204;
        }
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

Typebot Botlab Config

server {
    if ($host = botlab.{client}.{domain}) {
        return 301 https://$host$request_uri;
    }

    client_max_body_size 64M;
    listen 80;
    server_name botlab.{client}.{domain};

    location / {
        return 301 https://$host$request_uri;
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

server {
    client_max_body_size 64M;
    large_client_header_buffers 4 16k;
    listen 443 ssl http2;
    server_name botlab.{client}.{domain};

    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://172.20.1.8:3000;
        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Typebot Bots Config

server {
    if ($host = bots.{client}.{domain}) {
        return 301 https://$host$request_uri;
    }

    client_max_body_size 64M;
    listen 80;
    server_name bots.{client}.{domain};

    location / {
        return 301 https://$host$request_uri;
    }

    location ^~ /.well-known/acme-challenge/ {
        alias /var/www/html/.well-known/acme-challenge/;
        default_type "text/plain";
        allow all;
    }
}

server {
    client_max_body_size 64M;
    large_client_header_buffers 4 16k;
    listen 443 ssl http2;
    server_name bots.{client}.{domain};

    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://172.20.1.9:3000;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Nginx Tips

Always do the link of the nginx files before requesting certs, but comment out any ssl locations.

# Link sites-available to sites-enabled
sudo ln -s /etc/nginx/sites-available/{config}.conf /etc/nginx/sites-enabled/

# Test nginx configuration
sudo nginx -t

# Reload nginx
sudo systemctl reload nginx

ToDo

  • Fix backups.sh