# Blog ImageGen Source: https://docs.trymondo.com/ai/blog-image-gen This is the introduction to the proposal experience at proposals.trymondo.com # Custom Image Generation for Blog Feature Images Mondo is going to be using custom image generation models that are highly tuned for style, quality, composure, speed, storage, and web-ready compression to spruce up ugly feature images on blogs. Example Blog Feature Image This image used a combination of Stable Diffusion and ChatGPT to generate a blog feature image for a post about AI. The image was generated using a custom model fine-tuned for the specific style and quality requirements of Mondo's blog. ## Goal The goal is to enhance the visual appeal of blog feature images by leveraging advanced image generation techniques. This will ensure that the images are not only aesthetically pleasing but also optimized for web performance. ## Approach 1. **On-Prem GPUs**: Utilize on-premises GPUs to handle the computationally intensive tasks of training and running custom image generation models. This approach ensures full control over the hardware and data, while also reducing dependency on cloud services. 2. **Open Source and Free Tools**: Leverage open-source and free tools to build and fine-tune the image generation models. This includes: * Frameworks like PyTorch or TensorFlow for model development. * Pre-trained models from repositories like Hugging Face or Stability AI as a starting point. * Tools for image optimization and compression, such as ImageMagick or TinyPNG. 3. **Custom Tuning**: Fine-tune the models to prioritize: * **Style**: Ensure the generated images align with the desired aesthetic. * **Quality**: Maintain high resolution and clarity. * **Composure**: Generate images with balanced composition and focus. * **Speed**: Optimize the models for fast inference times. * **Storage**: Minimize file sizes without compromising quality. * **Web-Ready Compression**: Ensure the images are optimized for fast loading on the web. By combining these strategies, Mondo will be able to generate high-quality, visually appealing, and web-optimized feature images for blogs efficiently and cost-effectively. # Ozzie AI Source: https://docs.trymondo.com/ai/client-llm This is the introduction to the proposal experience at proposals.trymondo.com # Mondo's Client LLM: Revolutionizing Business Insights Mondo is building its own Client LLM (Large Language Model) to empower small businesses with instant access to comprehensive insights. This cutting-edge solution will consolidate all client-related data, including past creative assets, posts, invoices, ad analytics, and more, into a single, intelligent system. By leveraging this technology, small businesses can gain ultimate business insights without incurring the exorbitant costs typically associated with such advanced tools. The Client LLM will streamline decision-making, enhance operational efficiency, and provide actionable recommendations tailored to each business's unique needs. Eventually, all these capabilities will be seamlessly integrated into a client-facing application called the **Mondo App**, delivering unparalleled value and accessibility to small businesses everywhere. # null Source: https://docs.trymondo.com/mops/apps/calcom ## Overview Cal.com is a scheduling and appointment management system integrated into the Mondo MOPS ecosystem. It provides a robust solution for managing appointments, scheduling meetings, and coordinating availability across team members. In the MOPS platform, Cal.com serves as the central scheduling infrastructure, accessible via its own subdomain. Cal.com was formerly known as Calendly and provides similar functionality with additional features for self-hosting and customization. ## Architecture Cal.com in the MOPS stack consists of: * **Cal.com Application Container**: The main application serving the web interface * **PostgreSQL Database**: Stores all scheduling data, accounts, and configuration * **Traefik Integration**: Handles routing and TLS termination ## Deployment Configuration ### Docker Compose Setup ```yaml theme={null} services: database: container_name: calcom-db image: postgres:17.4 restart: unless-stopped volumes: - ./db:/var/lib/postgresql/data/ environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} env_file: .env networks: - calcom-net healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER}'] interval: 5s timeout: 5s retries: 5 calcom: image: calcom/cal.com:v5.0.19 container_name: calcom-app restart: unless-stopped volumes: - ./data:/app/data networks: - traefik-net - calcom-net ports: - 3000:3000 env_file: .env environment: # Database Configuration - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@calcom-db:5432/${POSTGRES_DB}?sslmode=disable - DATABASE_DIRECT_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@calcom-db:5432/${POSTGRES_DB}?sslmode=disable # Google Calendar Integration - GOOGLE_API_CREDENTIALS=${GOOGLE_API_CREDENTIALS} # SAML Configuration - SAML_DATABASE_URL=${SAML_DATABASE_URL} - SAML_ADMINS=${SAML_ADMINS} # Security and Auth - NEXTAUTH_SECRET=${NEXTAUTH_SECRET} - CALENDSO_ENCRYPTION_KEY=${CALENDSO_ENCRYPTION_KEY} - NEXTAUTH_URL=https://cal.trymondo.com # Application URLs - NEXT_PUBLIC_WEBAPP_URL=https://cal.trymondo.com - NEXT_PUBLIC_APP_URL=https://cal.trymondo.com - NEXT_PUBLIC_API_V2_URL=https://cal.trymondo.com/api/v2 - WEBAPP_URL=https://cal.trymondo.com - APP_URL=https://cal.trymondo.com # Hostname Configuration - ALLOWED_HOSTNAMES="cal.trymondo.com,trymondo.com,localhost:3000" # Email Configuration - EMAIL_FROM=info@trymondo.com - MAIL_FROM=info@trymondo.com # SMTP Configuration - SMTP_HOST=smtp.mailersend.net - SMTP_PORT=587 - SMTP_USERNAME=${SMTP_USERNAME} - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_SECURE=false - SMTP_AUTH_TYPE=LOGIN - SMTP_IGNORE_TLS=false # Nodemailer Configuration - EMAIL_SERVER_HOST=${SMTP_HOST} - EMAIL_SERVER_PORT=587 - EMAIL_SERVER_USER=${EMAIL_SERVER_USER} - EMAIL_SERVER_PASSWORD=${EMAIL_SERVER_PASSWORD} # Force SMTP over sendmail - EMAIL_TRANSPORT=smtp - SENDMAIL_DISABLED=true - MAILER_PROVIDER=smtp # Debug - DEBUG=email:*,nodemailer:*,prisma:* - EMAIL_DEBUG=true - NODE_TLS_REJECT_UNAUTHORIZED=0 # Application Settings - NEXT_PUBLIC_LICENSE_CONSENT=true - CALCOM_TELEMETRY_DISABLED=1 - NEXT_PUBLIC_IS_E2E=0 - NEXT_PUBLIC_IS_PREMIUM=true - NEXT_PUBLIC_TEAM_IMPERSONATION=false - NEXT_DISABLE_IMPERSONATION_PAGE=true depends_on: - database labels: - 'traefik.enable=true' - 'traefik.http.routers.cal.rule=Host(`cal.trymondo.com`)' - 'traefik.http.routers.cal.entrypoints=websecure' - 'traefik.http.routers.cal.tls=true' - 'traefik.http.routers.cal.tls.certresolver=production' - 'traefik.http.services.cal.loadbalancer.server.scheme=http' - 'traefik.http.services.cal.loadbalancer.server.port=3000' - 'traefik.http.routers.cal.middlewares=cors@file,secureHeaders@file' networks: traefik-net: external: true calcom-net: external: true ``` ## Configuration ### Environment Variables Create a `.env` file in the Cal.com directory with the following variables: ``` # Database Configuration POSTGRES_USER=your_db_username POSTGRES_PASSWORD=your_db_password POSTGRES_DB=calcom # Security Keys NEXTAUTH_SECRET=your_random_secret_string CALENDSO_ENCRYPTION_KEY=your_32_character_key # Google Calendar (Optional) GOOGLE_API_CREDENTIALS={"web":{"client_id":"your_client_id","project_id":"your_project_id","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"your_client_secret","redirect_uris":["https://cal.trymondo.com/api/auth/callback/google"],"javascript_origins":["https://cal.trymondo.com"]}} # SAML Configuration (Optional) SAML_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@calcom-db:5432/${POSTGRES_DB}?sslmode=disable SAML_ADMINS=admin@your-domain.com # SMTP Configuration SMTP_USERNAME=your_smtp_username SMTP_PASSWORD=your_smtp_password EMAIL_SERVER_USER=your_email_username EMAIL_SERVER_PASSWORD=your_email_password ``` Store these credentials securely. The `.env` file contains sensitive information that should not be committed to version control. ### Key Configuration Options | Setting | Description | Example | | --------------------------- | --------------------------------------- | ------------------------------- | | `ALLOWED_HOSTNAMES` | Comma-separated list of valid hostnames | `cal.trymondo.com,trymondo.com` | | `NEXTAUTH_URL` | URL for authentication | `https://cal.trymondo.com` | | `NEXT_PUBLIC_WEBAPP_URL` | Public-facing URL | `https://cal.trymondo.com` | | `SMTP_*` | Email configuration | Settings for your SMTP provider | | `CALCOM_TELEMETRY_DISABLED` | Disable usage tracking | `1` | | `EMAIL_DEBUG` | Enable email debugging | `true` for troubleshooting | ## Installation and Setup ### Prerequisites * Docker and Docker Compose installed * External `traefik-net` network created * Domain with DNS pointing to your server * SMTP credentials for email notifications ### Deployment Steps 1. **Create Required Networks**: ```bash theme={null} docker network create calcom-net # Ensure traefik-net exists docker network ls | grep traefik-net || docker network create traefik-net ``` 2. **Prepare Directory Structure**: ```bash theme={null} mkdir -p /opt/apps/calcom/{db,data} cd /opt/apps/calcom ``` 3. **Create Configuration Files**: ```bash theme={null} # Create docker-compose.yml using the configuration above nano docker-compose.yml # Create .env file with required variables nano .env ``` 4. **Deploy the Stack**: ```bash theme={null} docker compose up -d ``` 5. **Monitor Initial Startup**: ```bash theme={null} docker compose logs -f ``` ### First-Time Setup Once deployed, complete the setup: 1. Visit `https://cal.trymondo.com` 2. Create the admin account 3. Configure organization settings 4. Set up event types and availability ## Integration with Other MOPS Services ### Authentication Cal.com can be integrated with Auth0 or other authentication providers: 1. Configure the OAuth provider in your authentication service 2. Add the appropriate callback URLs 3. Update the Cal.com environment variables with the OAuth credentials ### API Integration Cal.com exposes an API that can be used by other MOPS services: ```bash theme={null} # Example API endpoint https://cal.trymondo.com/api/v2/ ``` ## Maintenance ### Backup and Restore Cal.com data is stored in two locations: 1. **PostgreSQL Database**: Use Backrest to back up the database volume 2. **Application Data**: The `./data` volume contains uploads and other files Regular backups should include both components: ```bash theme={null} # Example backup using docker commands docker exec calcom-db pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} > calcom_backup_$(date +%Y%m%d).sql # Example restore cat calcom_backup_20250415.sql | docker exec -i calcom-db psql -U ${POSTGRES_USER} ${POSTGRES_DB} ``` ### Updates To update Cal.com: 1. Update the image tag in docker-compose.yml 2. Pull the new image: ```bash theme={null} docker compose pull ``` 3. Apply the update: ```bash theme={null} docker compose up -d ``` Always create a backup before updating to prevent data loss. ## Troubleshooting ### Common Issues | Issue | Solution | | -------------------------- | -------------------------------------------------------- | | Database connection errors | Check PostgreSQL container health and connection string | | Email not sending | Verify SMTP settings and check logs with `DEBUG=email:*` | | White screen after update | Check application logs for JavaScript errors | | Authentication issues | Verify `NEXTAUTH_URL` and `NEXTAUTH_SECRET` settings | ### Checking Logs ```bash theme={null} # View application logs docker logs calcom-app # View database logs docker logs calcom-db # Follow logs in real-time docker logs -f calcom-app ``` ### Health Checks ```bash theme={null} # Check database health docker exec calcom-db pg_isready -U ${POSTGRES_USER} # Check application health curl -kI https://cal.trymondo.com ``` ## Performance Tuning ### Resource Allocation Cal.com performs well with moderate resources: * Database: 1 CPU, 1GB RAM * Application: 1-2 CPU, 2GB RAM For high-traffic instances, consider adding resource constraints to docker-compose.yml: ```yaml theme={null} services: database: deploy: resources: limits: memory: 1G cpus: '1' calcom: deploy: resources: limits: memory: 2G cpus: '2' ``` ## Security Considerations 1. **Database Access**: Limit access to the PostgreSQL database 2. **SMTP Credentials**: Regularly rotate email credentials 3. **API Security**: Monitor API usage and restrict access as needed 4. **Traefik Configuration**: Ensure proper security headers are applied (already configured) ## References * [Cal.com Documentation](https://cal.com/docs) * [Cal.com GitHub Repository](https://github.com/calcom/cal.com) * [PostgreSQL Documentation](https://www.postgresql.org/docs/) *** This documentation provides a comprehensive guide to deploying, configuring, and maintaining Cal.com within the Mondo MOPS ecosystem. For specific customization needs or advanced features, refer to the official Cal.com documentation. # null Source: https://docs.trymondo.com/mops/apps/espocrm ## Overview This guide covers the deployment and configuration of EspoCRM using Docker Compose behind Traefik reverse proxy. EspoCRM serves as Mondo's customer relationship management solution, accessible at `crm.trymondo.com`. ## Architecture EspoCRM is deployed as a multi-container application with the following components: * **MariaDB**: Database server storing EspoCRM data * **EspoCRM**: Main application container * **EspoCRM Daemon**: Background process container * **EspoCRM WebSocket**: Real-time communications container All services use the external `traefik-net` network for routing through Traefik. ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External `traefik-net` network * DNS configured for `crm.trymondo.com` ## Deployment ### Directory Structure ``` environments/prod/espocrm/ ├── docker-compose.yml # Main configuration file ├── .env # Environment variables (not in repo) ``` ### Environment Variables Create a `.env` file with the following variables: ``` MYSQL_ROOT_PASSWORD=your_secure_password MYSQL_DATABASE=espocrm MYSQL_USER=espocrm_user MYSQL_PASSWORD=your_secure_password ESPO_ADMIN_USERNAME=admin ESPO_ADMIN_PASSWORD=your_secure_password ESPO_SITE_URL=https://crm.trymondo.com ``` Never commit the `.env` file to version control. Store passwords securely in your password manager. ### Docker Compose Configuration The deployment uses a shared image reference and multiple service definitions: ```yaml theme={null} x-espocrm-image: &espocrm-image image: espocrm/espocrm:9.0.8 services: mariadb: image: mariadb:11.7.2 container_name: espocrm-db restart: unless-stopped init: true environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} volumes: - mariadb-data:/var/lib/mysql healthcheck: test: [ 'CMD-SHELL', 'mariadb-admin ping -h 127.0.0.1 -u root -p$${MYSQL_ROOT_PASSWORD}', ] interval: 10s timeout: 5s retries: 5 start_period: 20s networks: - espocrm-net espocrm: <<: *espocrm-image container_name: espocrm restart: unless-stopped init: true depends_on: mariadb: condition: service_healthy environment: ESPOCRM_DATABASE_DRIVER: mysql ESPOCRM_DATABASE_HOST: mariadb ESPOCRM_DATABASE_USER: ${MYSQL_USER} ESPOCRM_DATABASE_PASSWORD: ${MYSQL_PASSWORD} ESPOCRM_DATABASE_NAME: ${MYSQL_DATABASE} ESPOCRM_ADMIN_USERNAME: ${ESPO_ADMIN_USERNAME} ESPOCRM_ADMIN_PASSWORD: ${ESPO_ADMIN_PASSWORD} ESPOCRM_SITE_URL: ${ESPO_SITE_URL} volumes: - html-data:/var/www/html healthcheck: test: ['CMD-SHELL', 'curl -sf http://localhost || exit 1'] interval: 10s timeout: 5s retries: 5 networks: - traefik-net - espocrm-net labels: - traefik.enable=true - traefik.http.routers.espocrm.rule=Host(`crm.trymondo.com`) - traefik.http.routers.espocrm.entrypoints=web,websecure - traefik.http.routers.espocrm.tls=true - traefik.http.routers.espocrm.tls.certresolver=production - traefik.http.services.espocrm.loadbalancer.server.port=80 - traefik.http.routers.espocrm.middlewares=secureHeaders@file espocrm-daemon: <<: *espocrm-image container_name: espocrm-daemon restart: unless-stopped init: true entrypoint: docker-daemon.sh depends_on: - espocrm volumes: - html-data:/var/www/html networks: - espocrm-net espocrm-websocket: <<: *espocrm-image container_name: espocrm-websocket restart: unless-stopped init: true entrypoint: docker-websocket.sh depends_on: - espocrm environment: ESPOCRM_CONFIG_USE_WEB_SOCKET: 'true' ESPOCRM_CONFIG_WEB_SOCKET_URL: 'wss://crm.trymondo.com/ws' ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBSCRIBER_DSN: 'tcp://*:7777' ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN: 'tcp://espocrm-websocket:7777' volumes: - html-data:/var/www/html networks: - traefik-net - espocrm-net labels: - traefik.enable=true - traefik.http.routers.espocrm-ws.rule=Host(`crm.trymondo.com`) && PathPrefix(`/ws`) - traefik.http.routers.espocrm-ws.entrypoints=web,websecure - traefik.http.routers.espocrm-ws.tls=true - traefik.http.routers.espocrm-ws.tls.certresolver=production - traefik.http.services.espocrm-ws.loadbalancer.server.port=80 volumes: mariadb-data: html-data: networks: traefik-net: external: true espocrm-net: external: true ``` ## Deployment Commands Deploy the stack with: ```bash theme={null} cd /opt/apps/espocrm docker compose up -d ``` Verify all components are running: ```bash theme={null} docker compose ps ``` ## Configuration Highlights ### Traefik Integration EspoCRM is configured with the following Traefik routing: * Main application at `crm.trymondo.com` * WebSocket endpoint at `crm.trymondo.com/ws` * TLS certificate managed by Traefik's `production` resolver * Security headers applied through Traefik middleware ### WebSocket Configuration Real-time communication is enabled through ZeroMQ and WebSockets: * WebSocket URL: `wss://crm.trymondo.com/ws` * Internal ZeroMQ communication between containers * Separate Traefik router rule for WebSocket traffic ### Volume Management The deployment uses Docker named volumes: * `mariadb-data`: Persistent storage for the database * `html-data`: Shared volume for EspoCRM application data across all containers ## Maintenance ### Backup Strategy EspoCRM data should be backed up regularly using Restic/Backrest: ```bash theme={null} # Backup database docker compose exec mariadb mysqldump -u root -p${MYSQL_ROOT_PASSWORD} ${MYSQL_DATABASE} > backup_$(date +%Y%m%d).sql # Include volumes in Backrest paths # /var/lib/docker/volumes/espocrm_mariadb-data # /var/lib/docker/volumes/espocrm_html-data ``` ### Updates To update EspoCRM: 1. Update the image version tag in `docker-compose.yml` 2. Pull the new image: ```bash theme={null} docker compose pull ``` 3. Deploy the updated stack: ```bash theme={null} docker compose up -d ``` 4. Check logs for any migration issues: ```bash theme={null} docker compose logs -f ``` ## Troubleshooting ### Database Connection Issues If EspoCRM can't connect to the database: 1. Check MariaDB container status: ```bash theme={null} docker compose ps mariadb ``` 2. Verify network connectivity: ```bash theme={null} docker compose exec espocrm ping mariadb ``` 3. Check database credentials: ```bash theme={null} docker compose exec mariadb mysql -u ${MYSQL_USER} -p${MYSQL_PASSWORD} -e "SHOW DATABASES;" ``` ### WebSocket Issues If real-time updates aren't working: 1. Check WebSocket container is running: ```bash theme={null} docker compose ps espocrm-websocket ``` 2. Verify WebSocket URL configuration matches the Traefik route. 3. Test WebSocket connectivity from browser developer tools. ### Traefik Routing Problems If the site is unreachable: 1. Check Traefik logs: ```bash theme={null} docker logs traefik ``` 2. Verify DNS resolution for `crm.trymondo.com` 3. Confirm Traefik network is correctly attached to all containers. ## Resources * [Official EspoCRM Docker Documentation](https://docs.espocrm.com/administration/docker/) * [MariaDB Documentation](https://mariadb.com/kb/en/documentation/) * [Traefik v2 Documentation](https://doc.traefik.io/traefik/v2.0/) ## Next Steps * Set up monitoring and alerting for EspoCRM services with Prometheus/Grafana * Implement automated backups of volumes and database dumps * Configure SMTP for email notifications * Explore EspoCRM API integrations with other Mondo services # null Source: https://docs.trymondo.com/mops/apps/filepizza ## Overview FilePizza is a browser-based, peer-to-peer file sharing service deployed as part of the Mondo Open Platform Service (MOPS). It allows users to share files directly between browsers using WebRTC technology, without storing files on a central server. ## Service Details | Component | Value | | --------- | -------------------------------------------------------- | | URL | [https://pizza.trymondo.com](https://pizza.trymondo.com) | | Image | kern/filepizza:latest | | Container | filepizza | | Port | 3000 (internal) | | Network | traefik-net (external) | ## Architecture FilePizza consists of a single container connected to the Traefik network: ``` [Client Browsers] <-- WebRTC P2P --> [Client Browsers] ↑ ↑ | | +-----------→ [FilePizza] ←---------+ ↑ | [Traefik] ``` FilePizza acts as a WebRTC signaling server to establish direct peer connections, but the file data transfers directly between browsers. ## Deployment Configuration ### Docker Compose File ```yaml theme={null} services: redis: image: redis:7.4.2 container_name: redis restart: unless-stopped ports: - 127.0.0.1:6379:6379 healthcheck: test: ['CMD', 'redis-cli', 'ping'] interval: 30s timeout: 10s retries: 5 networks: - filepizza-net volumes: - filepizza-redis-data:/data # coturn: # image: coturn/coturn:4.6.3 # container_name: coturn # restart: unless-stopped # ports: # - 3478:3478 # - 3478:3478/udp # - 5349:5349 # - 5349:5349/udp # - 60000-60128:60000-60128/udp # environment: # - DETECT_EXTERNAL_IP=yes # - DETECT_RELAY_IP=yes # command: -n --log-file=stdout --redis-userdb="ip=redis connect_timeout=30" --min-port=60000 --max-port=60128 # networks: # - traefik-net # - filepizza-net # labels: # - traefik.enable=true # - traefik.http.routers.coturn.rule=Host(`coturn.trymondo.com`) # - traefik.http.routers.coturn.entrypoints=websecure # - traefik.http.routers.coturn.tls=true # - traefik.http.routers.coturn.tls.certresolver=production # - traefik.http.services.coturn.loadbalancer.server.port=3478 filepizza: image: kern/filepizza:7e8650f container_name: filepizza restart: unless-stopped environment: - PORT=80 - REDIS_URL=redis://redis:6379 - COTURN_ENABLED=false networks: - traefik-net - filepizza-net depends_on: - redis labels: - traefik.enable=true - traefik.http.routers.filepizza.rule=Host(`pizza.trymondo.com`) - traefik.http.routers.filepizza.entrypoints=websecure - traefik.http.routers.filepizza.tls=true - traefik.http.routers.filepizza.tls.certresolver=production - traefik.http.services.filepizza.loadbalancer.server.port=80 networks: traefik-net: external: true filepizza-net: external: true volumes: filepizza-redis-data: ``` ## Deployment Instructions 1. Create the deployment directory: ```bash theme={null} mkdir -p /opt/apps/filepizza ``` 2. Create the `docker-compose.yml` file with the content shown above: ```bash theme={null} nano /opt/apps/filepizza/docker-compose.yml ``` 3. Deploy the service: ```bash theme={null} cd /opt/apps/filepizza docker compose up -d ``` 4. Verify the service is running: ```bash theme={null} docker compose ps ``` ## Traefik Integration FilePizza is configured with the following Traefik settings: * **Host Rule**: `pizza.trymondo.com` * **Entrypoint**: websecure (HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 3000 ## Usage 1. Access the service at `https://pizza.trymondo.com` 2. File senders can: * Select a file to share * Receive a unique URL to share with recipients 3. File recipients: * Open the shared URL * Download the file directly from the sender's browser ## Important Notes FilePizza requires WebRTC support in browsers. Some corporate firewalls or restrictive networks might block WebRTC connections. FilePizza is a stateless application. No persistent volumes are needed as files are never stored on the server. ## Resource Usage FilePizza is a lightweight application with minimal resource requirements: * **Memory**: Typically less than 100MB * **CPU**: Minimal usage during idle periods, moderate during connection establishment ## Maintenance ### Updates To update FilePizza to the latest version: ```bash theme={null} cd /opt/apps/filepizza docker compose pull docker compose up -d ``` ### Troubleshooting If the service is inaccessible: 1. Check container status: ```bash theme={null} docker compose ps ``` 2. View container logs: ```bash theme={null} docker compose logs ``` 3. Verify Traefik routing: ```bash theme={null} curl -I -H "Host: pizza.trymondo.com" https://pizza.trymondo.com ``` ## Security Considerations * FilePizza doesn't store files, reducing data exposure risks * All communications go through HTTPS via Traefik * WebRTC connections are encrypted by default * Consider adding Traefik middleware for additional security: ```yaml theme={null} - traefik.http.routers.filepizza.middlewares=secureHeaders@file ``` ## Additional Resources * [FilePizza GitHub Repository](https://github.com/kern/filepizza) * [WebRTC Documentation](https://webrtc.org/) # Dashboard Source: https://docs.trymondo.com/mops/apps/homer dash.trymondo.com is the first place to go to see an overview of all the services on the MOPS platform. Homepager ## Overview **Homer** is a simple, static dashboard that allows you to organize your server applications and bookmarks into a clean, modern interface. This document covers the deployment and configuration of Homer using Docker Compose with Traefik as a reverse proxy. ## Service Details | Component | Value | | -------------- | ------------------------------------------------------ | | URL | [https://dash.trymondo.com](https://dash.trymondo.com) | | Image | b4bz/homer:v25.04.1 | | Container Name | homer | | Port | 8080 (internal) | | Network | traefik-net (external) | | Volume | ./assets (configuration and customization) | ## Architecture Homer is deployed as a single container that serves a static dashboard: ``` ┌─────────────┐ HTTPS Request │ Traefik │ ─────────────────▶│ │ └──────┬──────┘ │ ▼ ┌─────────────┐ │ Homer │ │ Dashboard │ └──────┬──────┘ │ ▼ ┌─────────────┐ │ ./assets │ │ Volume │ └─────────────┘ ``` * **Traefik**: Provides HTTPS termination and routing * **Homer Container**: Serves the static dashboard * **Assets Volume**: Contains configuration and customization files ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External `traefik-net` network * DNS configured for `dash.trymondo.com` ## Deployment Configuration ### Directory Structure ``` /opt/apps/homer/ ├── docker-compose.yml # Main configuration file ├── docker-compose.override.yml # (Optional) Resource limits └── assets/ # Homer configuration files ├── config.yml # Dashboard configuration ├── icons/ # Custom icons └── logos/ # Custom logos ``` ### Docker Compose File ```yaml theme={null} services: homer: image: b4bz/homer:v25.04.1 container_name: homer volumes: - ./assets:/www/assets environment: - INIT_ASSETS=1 labels: - 'traefik.enable=true' - 'traefik.http.routers.homer.rule=Host(`dash.trymondo.com`)' - 'traefik.http.routers.homer.entrypoints=websecure' - 'traefik.http.routers.homer.tls=true' - 'traefik.http.routers.homer.tls.certresolver=production' - 'traefik.http.services.homer.loadbalancer.server.port=8080' - 'traefik.http.routers.homer.middlewares=secureHeaders@file' - 'diun.enable=true' networks: - traefik-net restart: unless-stopped networks: traefik-net: external: true ``` ### Resource Limits (Optional) For improved stability, you can add resource constraints using a `docker-compose.override.yml` file: ```yaml theme={null} services: homer: deploy: resources: limits: memory: 128M cpus: '0.2' ``` ## Deployment Instructions 1. Create the deployment directory: ```bash theme={null} mkdir -p /opt/apps/homer/assets ``` 2. Create the `docker-compose.yml` file: ```bash theme={null} nano /opt/apps/homer/docker-compose.yml ``` 3. Create the optional resource limits file: ```bash theme={null} nano /opt/apps/homer/docker-compose.override.yml ``` 4. Deploy the service: ```bash theme={null} cd /opt/apps/homer docker compose up -d ``` 5. Verify the service is running: ```bash theme={null} docker compose ps ``` ## Configuration ### Basic `config.yml` Setup After deploying Homer, you'll need to configure your dashboard. When the `INIT_ASSETS=1` environment variable is set, Homer will create a default configuration on first launch. Edit the configuration file: ```bash theme={null} nano /opt/apps/homer/assets/config.yml ``` Here's a basic example configuration: ```yaml theme={null} --- title: 'Mondo Dashboard' subtitle: 'Self-hosted services' logo: 'logo.png' # Optional theme customization theme: default colors: light: primary: '#3367d6' dark: primary: '#3367d6' # Optional message message: style: 'is-info' title: 'Welcome to the Mondo MOPS Dashboard!' content: 'This dashboard provides quick access to all Mondo services.' # Services displayed on the dashboard services: - name: 'DevOps' icon: 'fas fa-code-branch' items: - name: 'Traefik' logo: 'assets/tools/traefik.png' subtitle: 'Reverse Proxy' tag: 'infrastructure' url: 'https://traefik.trymondo.com' - name: 'Portainer' logo: 'assets/tools/portainer.png' subtitle: 'Container Management' tag: 'infrastructure' url: 'https://portainer.trymondo.com' - name: 'Gitea' logo: 'assets/tools/gitea.png' subtitle: 'Git Server' tag: 'tools' url: 'https://git.trymondo.com' - name: 'Applications' icon: 'fas fa-cloud' items: - name: 'Outline Wiki' logo: 'assets/tools/outline.png' subtitle: 'Knowledge Base' tag: 'app' url: 'https://wiki.trymondo.com' - name: 'Mautic' logo: 'assets/tools/mautic.png' subtitle: 'Marketing Automation' tag: 'app' url: 'https://outreach.trymondo.com' - name: 'N8N' logo: 'assets/tools/n8n.png' subtitle: 'Workflow Automation' tag: 'app' url: 'https://automations.trymondo.com' ``` ### Custom Icons and Logos You can add custom icons and logos to your dashboard: 1. Create directories for your assets: ```bash theme={null} mkdir -p /opt/apps/homer/assets/icons mkdir -p /opt/apps/homer/assets/logos mkdir -p /opt/apps/homer/assets/tools ``` 2. Add your custom images to these directories 3. Reference them in your `config.yml` file ### Theme Customization Homer supports multiple themes. To change the theme, update the `theme` property in `config.yml`: ```yaml theme={null} # Available themes: default, sui, slate, minimal theme: minimal # Custom colors colors: light: primary: '#34495e' background: '#f5f5f5' dark: primary: '#3498db' background: '#222222' ``` ## Traefik Integration Homer is configured with the following Traefik settings: * **Host Rule**: `dash.trymondo.com` * **Entrypoint**: websecure (HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 8080 * **Middleware**: secureHeaders for enhanced security ## Update Monitoring Homer is configured with Diun monitoring to automatically detect image updates: ```yaml theme={null} labels: - 'diun.enable=true' ``` When a new version of the Homer image is available, Diun will send a notification. ## Maintenance ### Backup Strategy Back up Homer's configuration regularly: ```bash theme={null} # Backup the assets directory tar -czf homer-assets-backup-$(date +%Y%m%d).tar.gz -C /opt/apps/homer assets ``` ### Updates To update Homer: 1. Update the image tag in `docker-compose.yml` 2. Apply the update: ```bash theme={null} cd /opt/apps/homer docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs ``` ## Troubleshooting ### Dashboard Not Loading If the dashboard is not loading: 1. Check if the container is running: ```bash theme={null} docker compose ps ``` 2. Verify the assets volume is correctly mounted: ```bash theme={null} docker compose exec homer ls -la /www/assets ``` 3. Check for errors in the logs: ```bash theme={null} docker compose logs ``` ### Configuration Issues If the dashboard does not reflect your configuration changes: 1. Verify the syntax of your `config.yml`: ```bash theme={null} cd /opt/apps/homer/assets yamllint config.yml ``` 2. Restart the container to reload the configuration: ```bash theme={null} docker compose restart ``` 3. Check file permissions: ```bash theme={null} chmod -R 755 /opt/apps/homer/assets ``` ## Advanced Customization ### Adding Message of the Day You can add a message of the day to your dashboard: ```yaml theme={null} message: style: 'is-warning' # Options: is-info, is-success, is-warning, is-danger title: 'System Maintenance' content: 'Scheduled maintenance on Friday from 2-4 PM MST.' ``` ### Grouping Services You can organize your services into groups: ```yaml theme={null} services: - name: 'Infrastructure' icon: 'fas fa-server' items: # Infrastructure services... - name: 'Marketing' icon: 'fas fa-bullhorn' items: # Marketing services... - name: 'Development' icon: 'fas fa-code' items: # Development services... ``` ### Custom CSS You can add custom CSS by creating a `custom.css` file: ```bash theme={null} nano /opt/apps/homer/assets/custom.css ``` Then reference it in your `config.yml`: ```yaml theme={null} stylesheet: 'assets/custom.css' ``` ## Additional Resources * [Official Homer Documentation](https://github.com/bastienwirtz/homer) * [Homer Demo Page](https://homer-demo.netlify.app/) * [Traefik Documentation](https://doc.traefik.io/traefik/) ## Integration Examples ### Adding Mondo Services Here's an example of how to add all Mondo services to your Homer dashboard: ```yaml theme={null} services: - name: 'Infrastructure' icon: 'fas fa-server' items: - name: 'Traefik' url: 'https://traefik.trymondo.com' - name: 'Portainer' url: 'https://portainer.trymondo.com' - name: 'Backrest' url: 'https://backrest.trymondo.com' - name: 'Marketing Tools' icon: 'fas fa-bullhorn' items: - name: 'Mautic' url: 'https://outreach.trymondo.com' - name: 'N8N' url: 'https://automations.trymondo.com' - name: 'EspoCRM' url: 'https://crm.trymondo.com' - name: 'Development' icon: 'fas fa-code' items: - name: 'Gitea' url: 'https://git.trymondo.com' - name: 'Woodpecker CI' url: 'https://ci.trymondo.com' - name: 'Collaboration' icon: 'fas fa-users' items: - name: 'Outline Wiki' url: 'https://wiki.trymondo.com' - name: 'Cal.com' url: 'https://cal.trymondo.com' - name: 'FilePizza' url: 'https://pizza.trymondo.com' ``` # null Source: https://docs.trymondo.com/mops/apps/mautic ## Overview Mautic is an open-source marketing automation platform deployed as part of the Mondo Open Platform Service (MOPS). This documentation covers the deployment, configuration, and management of Mautic using Docker Compose with Traefik as a reverse proxy. ## Service Details | Component | Value | | ---------- | -------------------------------------------------------------- | | URL | [https://outreach.trymondo.com](https://outreach.trymondo.com) | | Image | mautic/mautic:5.2.4-apache | | Containers | mautic\_web, mautic\_cron, mautic\_worker, mautic\_db | | Database | MySQL 8.0 | | Networks | traefik-net, mautic-net | ## Architecture Mautic is deployed as a multi-container application with the following components: ``` ┌─────────────┐ │ Traefik │ └──────┬──────┘ │ HTTPS ▼ ┌─────────────┐ ┌──────────────┐ │ Mautic Cron │◄────▶│ Mautic Web │ └─────────────┘ └──────┬───────┘ ▲ │ │ ▼ │ ┌──────────────┐ └─────────────┤ MySQL DB │ └──────────────┘ ▲ ┌─────────────┐ │ │Mautic Worker│◄────────────┘ └─────────────┘ ``` * **Mautic Web**: Main application container serving the UI and API * **Mautic Cron**: Runs scheduled tasks for email campaigns, etc. * **Mautic Worker**: Processes queue jobs like email sending * **MySQL Database**: Stores all Mautic data ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External networks: `traefik-net` and `mautic-net` * DNS configured for `outreach.trymondo.com` ## Deployment Configuration ### Directory Structure ``` /opt/apps/mautic/ ├── docker-compose.yml # Main configuration file ├── docker-compose.override.yml # Resource limits ├── .mautic.env # Mautic configuration ├── .env # Database credentials ├── mautic/ │ ├── config/ # Configuration files │ ├── logs/ # Log files │ └── media/ # Uploads └── cron/ # Cron job configuration ``` ### Environment Variables Create a `.env` file with the following variables: ``` MYSQL_ROOT_PASSWORD=secure_root_password MYSQL_DATABASE=mautic MYSQL_USER=mautic_user MYSQL_PASSWORD=secure_user_password MAUTIC_PORT=8001 DOCKER_MAUTIC_LOAD_TEST_DATA=false DOCKER_MAUTIC_RUN_MIGRATIONS=true ``` Create a `.mautic.env` file with additional Mautic-specific configurations (not shown in the provided files). ### Docker Compose Configuration ```yaml theme={null} x-mautic-volumes: &mautic-volumes - ./mautic/config:/var/www/html/config:z - ./mautic/logs:/var/www/html/var/logs:z - ./mautic/media/files:/var/www/html/docroot/media/files:z - ./mautic/media/images:/var/www/html/docroot/media/images:z - ./cron:/opt/mautic/cron:z - mautic-docroot:/var/www/html/docroot:z services: db: image: mysql:8.0 container_name: mautic_db environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_USER=${MYSQL_USER} - MYSQL_PASSWORD=${MYSQL_PASSWORD} volumes: - mysql-data:/var/lib/mysql healthcheck: test: mysqladmin --user=$$MYSQL_USER --password=$$MYSQL_PASSWORD ping start_period: 5s interval: 5s timeout: 5s retries: 10 networks: - mautic-net restart: unless-stopped mautic_web: image: mautic/mautic:5.2.4-apache links: - db:mysql ports: - ${MAUTIC_PORT:-8001}:80 volumes: *mautic-volumes container_name: mautic_web environment: - DOCKER_MAUTIC_LOAD_TEST_DATA=${DOCKER_MAUTIC_LOAD_TEST_DATA} - DOCKER_MAUTIC_RUN_MIGRATIONS=${DOCKER_MAUTIC_RUN_MIGRATIONS} env_file: - .mautic.env healthcheck: test: curl http://localhost start_period: 5s interval: 5s timeout: 5s retries: 100 depends_on: db: condition: service_healthy networks: - traefik-net - mautic-net labels: - 'traefik.enable=true' - 'traefik.http.routers.mautic.rule=Host(`outreach.trymondo.com`)' - 'traefik.http.routers.mautic.entrypoints=websecure' - 'traefik.http.routers.mautic.tls=true' - 'traefik.http.routers.mautic.tls.certresolver=production' - 'traefik.http.services.mautic.loadbalancer.server.scheme=http' - 'traefik.http.services.mautic.loadbalancer.server.port=80' - 'traefik.http.routers.mautic.middlewares=cors@file,secureHeaders@file' restart: unless-stopped mautic_cron: image: mautic/mautic:5.2.4-apache links: - db:mysql volumes: *mautic-volumes container_name: mautic_cron environment: - DOCKER_MAUTIC_ROLE=mautic_cron env_file: - .mautic.env depends_on: mautic_web: condition: service_healthy networks: - mautic-net restart: unless-stopped mautic_worker: image: mautic/mautic:5.2.4-apache links: - db:mysql volumes: *mautic-volumes container_name: mautic_worker environment: - DOCKER_MAUTIC_ROLE=mautic_worker env_file: - .mautic.env depends_on: mautic_web: condition: service_healthy networks: - mautic-net restart: unless-stopped volumes: mysql-data: mautic-docroot: networks: traefik-net: external: true mautic-net: external: true ``` ### Resource Limits (Optional) For improved stability, add resource constraints using a `docker-compose.override.yml` file: ```yaml theme={null} services: db: deploy: resources: limits: memory: 512M cpus: '0.2' mautic_web: deploy: resources: limits: memory: 384M cpus: '0.5' mautic_cron: deploy: resources: limits: memory: 320M cpus: '0.2' mautic_worker: deploy: resources: limits: memory: 512M cpus: '0.3' ``` ## Network Configuration Before deployment, ensure the required networks exist: ```bash theme={null} # Create external networks if they don't exist docker network create mautic-net docker network create traefik-net ``` ## Deployment Instructions 1. Create the deployment directory structure: ```bash theme={null} mkdir -p /opt/apps/mautic/{mautic/{config,logs,media/{files,images}},cron} ``` 2. Create the configuration files: ```bash theme={null} touch /opt/apps/mautic/.env touch /opt/apps/mautic/.mautic.env nano /opt/apps/mautic/docker-compose.yml nano /opt/apps/mautic/docker-compose.override.yml ``` 3. Add appropriate content to the `.env` and `.mautic.env` files 4. Deploy the service: ```bash theme={null} cd /opt/apps/mautic docker compose up -d ``` 5. Verify the services are running: ```bash theme={null} docker compose ps ``` ## Traefik Integration Mautic is configured with the following Traefik settings: * **Host Rule**: `outreach.trymondo.com` * **Entrypoint**: websecure (HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 80 * **Middlewares**: CORS and secure headers ## Webflow Integration Mautic can be integrated with Webflow forms using JavaScript tracking. Add the following code to your Webflow site: ```javascript theme={null} document.addEventListener('DOMContentLoaded', function () { const form = document.getElementById('leadForm'); const emailField = document.getElementById('Email-7'); const firstNameField = document.getElementById('First-Name'); const lastNameField = document.getElementById('Last-Name'); form.addEventListener('submit', function (event) { const email = emailField.value; const firstName = firstNameField.value; const lastName = lastNameField.value; // Identify contact in Mautic mt('send', 'pageview', { email: email, firstname: firstName, lastname: lastName, }); // Let the form submit normally setTimeout(function () { form.submit(); }, 300); // short delay to ensure tracking call completes }); }); ``` ## Maintenance ### Backup Strategy Back up Mautic regularly: ```bash theme={null} # Stop the services docker compose stop # Backup the database docker compose exec db mysqldump -u root -p${MYSQL_ROOT_PASSWORD} ${MYSQL_DATABASE} > mautic_backup_$(date +%Y%m%d).sql # Backup volumes tar -czf mautic_data_backup_$(date +%Y%m%d).tar.gz -C /opt/apps/mautic mautic # Restart the services docker compose start ``` ### Updates To update Mautic: 1. Update the image tag in `docker-compose.yml` 2. Apply the update: ```bash theme={null} cd /opt/apps/mautic docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs ``` Always back up your data before updating Mautic to a new version. ## Troubleshooting ### Database Connection Issues If Mautic can't connect to the database: 1. Verify MySQL container is running: ```bash theme={null} docker compose ps db ``` 2. Check database logs: ```bash theme={null} docker compose logs db ``` 3. Verify credentials in `.env` file match what Mautic is using ### Email Configuration Problems If emails are not being sent: 1. Check worker logs: ```bash theme={null} docker compose logs mautic_worker ``` 2. Verify SMTP settings in Mautic's configuration 3. Ensure the worker container has proper network access to the SMTP server ### Web Interface Not Accessible If you can't access the Mautic interface: 1. Check container health: ```bash theme={null} docker compose ps ``` 2. Verify Traefik routing: ```bash theme={null} docker compose logs mautic_web | grep -i "traefik" ``` 3. Check for any error logs: ```bash theme={null} docker compose logs mautic_web ``` ## Performance Optimization For improved performance: 1. **Increase Memory Limits**: Adjust values in `docker-compose.override.yml` if needed 2. **Database Tuning**: Consider adding MySQL configuration for better performance 3. **Caching**: Enable Redis if needed for larger installations ## Additional Resources * [Official Mautic Documentation](https://docs.mautic.org/) * [Mautic Docker Image Documentation](https://github.com/mautic/docker-mautic) * [Traefik Documentation](https://doc.traefik.io/traefik/) * [MySQL Documentation](https://dev.mysql.com/doc/) ## Integration Examples ### Mautic Forms Example of embedding a Mautic form on a website: ```html theme={null}
``` # null Source: https://docs.trymondo.com/mops/apps/n8n ## Overview n8n is a powerful workflow automation platform that allows you to connect various services and applications to create automated workflows. This document covers the deployment and configuration of n8n using Docker Compose with Traefik as a reverse proxy. ## Service Details | Component | Value | | ------------ | -------------------------------------------------------------------- | | URL | [https://automations.trymondo.com](https://automations.trymondo.com) | | Image | n8nio/n8n:1.88.0 | | Container | n8n | | Database | PostgreSQL 17.4 | | Networks | traefik-net, n8n-net | | Data Storage | ./data directory | ## Architecture n8n is deployed as a multi-container application with the following components: ``` ┌─────────────┐ │ Traefik │ └──────┬──────┘ │ HTTPS ▼ ┌──────────────┐ │ n8n │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ PostgreSQL │ └──────────────┘ ``` * **n8n**: Main application container serving the workflow editor and execution engine * **PostgreSQL**: Database for storing workflows, credentials, and execution data ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External networks: `traefik-net` and `n8n-net` * DNS configured for `automations.trymondo.com` * SMTP credentials for email notifications ## Deployment Configuration ### Environment Variables Create a `.env` file with the following variables: ``` # n8n Host Configuration N8N_HOST=automations.trymondo.com # Database Configuration DB_POSTGRESDB_DATABASE=n8n DB_POSTGRESDB_USER=n8n_user DB_POSTGRESDB_PASSWORD=secure_password_here # SMTP Configuration N8N_SMTP_USER=your_smtp_username N8N_SMTP_PASS=your_smtp_password # Security Configuration N8N_BASIC_AUTH_USER=admin_username N8N_BASIC_AUTH_PASSWORD=secure_admin_password N8N_ENCRYPTION_KEY=random_32_character_string ``` Generate a secure, random string for N8N\_ENCRYPTION\_KEY. This is used to encrypt credentials and sensitive data. You can generate a secure random string with: `bash openssl rand -hex 16 ` ### Docker Compose File ```yaml theme={null} services: n8n: image: n8nio/n8n:1.88.0 container_name: n8n restart: unless-stopped environment: - N8N_HOST=${N8N_HOST} - N8N_PORT=5678 - N8N_PROTOCOL=http - N8N_EDITOR_BASE_URL=https://${N8N_HOST} - WEBHOOK_URL=https://${N8N_HOST} - N8N_PATH=/ - N8N_LISTEN_ADDRESS=0.0.0.0 - N8N_PERSONALIZATION_ENABLED=true - DB_TYPE=postgresdb - DB_POSTGRESDB_HOST=db - DB_POSTGRESDB_DATABASE=${DB_POSTGRESDB_DATABASE} - DB_POSTGRESDB_USER=${DB_POSTGRESDB_USER} - DB_POSTGRESDB_PASSWORD=${DB_POSTGRESDB_PASSWORD} - DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_SCHEMA=public - DB_POSTGRESDB_SSL_ENABLED=false - N8N_EMAIL_MODE=smtp - N8N_SMTP_HOST=smtp.mailersend.net - N8N_SMTP_PORT=587 - N8N_SMTP_USER=${N8N_SMTP_USER} - N8N_SMTP_PASS=${N8N_SMTP_PASS} - N8N_SMTP_SENDER=info@trymondo.com - N8N_BASIC_AUTH_ACTIVE=true - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER} - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD} - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} - N8N_TRUST_PROXY=true - N8N_USE_X_FORWARDED_HOST=true - N8N_RUNNERS_ENABLED=true - EXECUTIONS_MODE=regular - EXECUTIONS_DATA_SAVE_ON_SUCCESS=none - EXECUTIONS_DATA_SAVE_ON_ERROR=all - EXECUTIONS_DATA_PRUNE=true - EXECUTIONS_DATA_MAX_AGE=336 - N8N_LOG_LEVEL=info - N8N_LOG_OUTPUT=console - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true - NODE_ENV=production - TZ=America/Denver volumes: - ./data:/home/node/.n8n depends_on: - db networks: - traefik-net - n8n-net labels: - 'traefik.enable=true' - 'traefik.http.routers.n8n.rule=Host(`automations.trymondo.com`)' - 'traefik.http.routers.n8n.entrypoints=websecure' - 'traefik.http.routers.n8n.tls.certresolver=production' - 'traefik.http.services.n8n.loadbalancer.server.port=5678' - 'traefik.http.services.n8n.loadbalancer.server.scheme=http' - 'traefik.http.routers.traefik.middlewares=rateLimit@file,secureHeaders@file' - 'traefik.docker.network=traefik-net' db: image: postgres:17.4 container_name: n8n-db restart: unless-stopped environment: - POSTGRES_DB=${DB_POSTGRESDB_DATABASE} - POSTGRES_USER=${DB_POSTGRESDB_USER} - POSTGRES_PASSWORD=${DB_POSTGRESDB_PASSWORD} volumes: - ./db:/var/lib/postgresql/data networks: - n8n-net networks: traefik-net: external: true n8n-net: external: true ``` ## Network Configuration Before deployment, ensure the required networks exist: ```bash theme={null} # Create external networks if they don't exist docker network create n8n-net docker network create traefik-net ``` ## Deployment Instructions 1. Create the deployment directory structure: ```bash theme={null} mkdir -p /opt/apps/n8n/{data,db} ``` 2. Create the configuration files: ```bash theme={null} nano /opt/apps/n8n/.env nano /opt/apps/n8n/docker-compose.yml ``` 3. Deploy the service: ```bash theme={null} cd /opt/apps/n8n docker compose up -d ``` 4. Verify the services are running: ```bash theme={null} docker compose ps ``` 5. Access n8n at `https://automations.trymondo.com` and log in with the credentials specified in the `.env` file. ## Traefik Integration n8n is configured with the following Traefik settings: * **Host Rule**: `automations.trymondo.com` * **Entrypoint**: websecure (HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 5678 * **Middlewares**: Rate limiting and secure headers ## Configuration Highlights ### Security Configuration n8n is configured with several security features: * **Basic Authentication**: Requires username/password to access the UI * **Encryption Key**: All sensitive data is encrypted at rest * **HTTPS**: All traffic is encrypted via Traefik * **Rate Limiting**: Prevents brute force attacks ### Workflow Execution Settings The n8n instance is configured with the following execution settings: * **Regular Execution Mode**: Workflows run in the main process * **Data Retention**: Error execution data is saved, successful executions are not * **Data Pruning**: Old execution data is automatically removed after 336 hours (14 days) * **Runners Enabled**: Allows distributed workflow execution ### Email Notifications Email is configured using SMTP with the following settings: * **SMTP Host**: smtp.mailersend.net * **SMTP Port**: 587 * **Sender**: [info@trymondo.com](mailto:info@trymondo.com) ## Maintenance ### Backup Strategy Back up n8n regularly using the following commands: ```bash theme={null} # Stop the services cd /opt/apps/n8n docker compose stop # Backup the database docker compose exec db pg_dump -U ${DB_POSTGRESDB_USER} ${DB_POSTGRESDB_DATABASE} > n8n_backup_$(date +%Y%m%d).sql # Backup n8n data tar -czf n8n_data_backup_$(date +%Y%m%d).tar.gz -C /opt/apps/n8n data # Restart the services docker compose start ``` ### Updates To update n8n: 1. Update the image tag in `docker-compose.yml` 2. Apply the update: ```bash theme={null} cd /opt/apps/n8n docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs ``` Always back up your data before updating n8n to a new version. ## Troubleshooting ### Database Connection Issues If n8n can't connect to the database: 1. Verify PostgreSQL container is running: ```bash theme={null} docker compose ps db ``` 2. Check database logs: ```bash theme={null} docker compose logs db ``` 3. Verify credentials in `.env` file match what n8n is using ### Webhook Issues If webhooks are not working correctly: 1. Verify the webhook URL configuration: ```bash theme={null} docker compose exec n8n node -e "console.log(process.env.WEBHOOK_URL)" ``` 2. Check that the URL is accessible from the internet 3. Verify Traefik is properly routing requests ### Authentication Problems If you're having trouble logging in: 1. Check the basic auth settings: ```bash theme={null} docker compose exec n8n node -e "console.log(process.env.N8N_BASIC_AUTH_ACTIVE)" ``` 2. Reset the admin password by updating the `.env` file and restarting the container ## Example Workflows ### Webflow Form to Mautic Integration This workflow captures form submissions from Webflow and adds contacts to Mautic: 1. Create a webhook node as the trigger 2. Copy the webhook URL to your Webflow form's action URL 3. Add a Mautic node to create/update contacts 4. Configure the mapping between Webflow form fields and Mautic contact fields ### Daily Database Backup Notification This workflow creates and notifies about database backups: 1. Set up a Cron node to trigger daily at a specific time 2. Add an Execute Command node to run pg\_dump 3. Add a Send Email node to notify about successful backups 4. Add error handling to notify about failures ## Security Considerations * **Credential Storage**: All API credentials are encrypted using the N8N\_ENCRYPTION\_KEY * **Basic Authentication**: The UI is protected with username/password * **HTTPS**: All traffic is encrypted via Traefik * **Database Security**: The PostgreSQL database is not exposed outside the Docker network * **Execution Data**: Only error execution data is saved to reduce sensitive data exposure ## Additional Resources * [Official n8n Documentation](https://docs.n8n.io/) * [n8n Docker Image Documentation](https://github.com/n8n-io/n8n/blob/master/docker/images/n8n/README.md) * [n8n Community Forums](https://community.n8n.io/) * [PostgreSQL Documentation](https://www.postgresql.org/docs/) * [Traefik Documentation](https://doc.traefik.io/traefik/) ## Integration with Other Mondo Services n8n can be integrated with other Mondo services: * **Mautic**: Use the Mautic nodes to manage contacts and campaigns * **EspoCRM**: Use HTTP Request nodes or custom nodes to interact with the CRM API * **Gitea**: Use Webhook triggers for repository events * **Traefik**: Ensure proper routing and HTTPS termination # null Source: https://docs.trymondo.com/mops/apps/outline ## Overview Outline is a modern team knowledge base and wiki platform deployed as part of the Mondo Open Platform Service (MOPS). This document covers the deployment and configuration of Outline using Docker Compose with Traefik as a reverse proxy. ## Service Details | Component | Value | | --------- | ------------------------------------------------------ | | URL | [https://wiki.trymondo.com](https://wiki.trymondo.com) | | Image | outlinewiki/outline:0.82.0 | | Database | PostgreSQL 17.4 | | Cache | Redis 7.4.2 | | Networks | traefik-net, outline-net | ## Architecture Outline is deployed as a multi-container application with the following components: ``` ┌─────────────┐ │ Traefik │ └──────┬──────┘ │ HTTPS ▼ ┌─────────────┐ ┌──────────────┐ │ Redis │◄────▶│ Outline │ └─────────────┘ └──────┬───────┘ │ ▼ ┌──────────────┐ │ PostgreSQL │ └──────────────┘ ``` * **Outline**: Main application container serving the wiki interface and API * **PostgreSQL**: Database for storing wiki content, users, and metadata * **Redis**: In-memory cache for improved performance ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External networks: `traefik-net` and `outline-net` * DNS configured for `wiki.trymondo.com` * Auth0 or other compatible OIDC provider * SMTP credentials for email notifications ## Deployment Configuration ### Environment Variables Create a `.env` file with the following variables: ``` # Security OUTLINE_SECRET_KEY=random_32_character_string OUTLINE_UTILS_SECRET=another_random_32_character_string # Authentication OIDC_CLIENT_ID=your_oidc_client_id OIDC_CLIENT_SECRET=your_oidc_client_secret AUTH0_DOMAIN=your_auth0_domain # Email SMTP_HOST=smtp.mailersend.net SMTP_USER=your_smtp_username SMTP_PASS=your_smtp_password SMTP_FROM_EMAIL=info@trymondo.com ``` Generate secure, random strings for OUTLINE\_SECRET\_KEY and OUTLINE\_UTILS\_SECRET. These are used to encrypt sensitive data and sign sessions. You can generate secure random strings with: `bash openssl rand -hex 16 ` ### Docker Compose File ````yaml theme={null} openssl rand -hex 16 ``` ### Docker Compose File ```yaml services: outline: image: outlinewiki/outline:0.82.0 container_name: outline depends_on: - postgres - redis environment: - NODE_ENV=production - URL=https://wiki.trymondo.com - SECRET_KEY=${OUTLINE_SECRET_KEY} - UTILS_SECRET=${OUTLINE_UTILS_SECRET} - DATABASE_URL=postgres://outline:outline@postgres:5432/outline - REDIS_URL=redis://redis:6379 - FILE_STORAGE=local - FILE_STORAGE_LOCAL_ROOT_DIR=/opt/outline/storage - FILE_STORAGE_UPLOAD_MAX_SIZE=26214400 - SMTP_HOST=${SMTP_HOST} - SMTP_PORT=587 - SMTP_USERNAME=${SMTP_USER} - SMTP_PASSWORD=${SMTP_PASS} - SMTP_FROM_EMAIL=${SMTP_FROM_EMAIL} - PGSSLMODE=disable - DATABASE_CONNECTION_POOL_MIN=2 - DATABASE_CONNECTION_POOL_MAX=10 - OIDC_CLIENT_ID=${OIDC_CLIENT_ID} - OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET} - OIDC_AUTH_URI=https://${AUTH0_DOMAIN}/authorize - OIDC_TOKEN_URI=https://${AUTH0_DOMAIN}/oauth/token - OIDC_USERINFO_URI=https://${AUTH0_DOMAIN}/userinfo - OIDC_DISPLAY_NAME=Auth0 labels: - 'traefik.enable=true' - 'traefik.http.routers.outline.rule=Host(`wiki.trymondo.com`)' - 'traefik.http.routers.outline.entrypoints=websecure' - 'traefik.http.routers.outline.tls=true' - 'traefik.http.routers.outline.tls.certresolver=production' - 'traefik.http.services.outline.loadbalancer.server.port=3000' - 'traefik.http.routers.outline.middlewares=secureHeaders@file' networks: - traefik-net - outline-net restart: unless-stopped user: '1001:1001' volumes: - ./data/uploads:/opt/outline/storage/uploads - ./data/logs:/opt/outline/logs postgres: image: postgres:17.4 container_name: outline_postgres restart: unless-stopped environment: - POSTGRES_USER=outline - POSTGRES_PASSWORD=outline - POSTGRES_DB=outline volumes: - ./data/db:/var/lib/postgresql/data networks: - outline-net redis: image: redis:7.4.2 container_name: outline_redis restart: unless-stopped networks: - outline-net networks: traefik-net: external: true outline-net: ```` ## Network Configuration Before deployment, ensure the required networks exist: ```bash theme={null} # Create external networks if they don't exist docker network create outline-net docker network create traefik-net ``` ## Deployment Instructions 1. Create the deployment directory structure: ```bash theme={null} mkdir -p /opt/apps/outline/data/{uploads,logs,db} ``` 2. Create the configuration files: ```bash theme={null} nano /opt/apps/outline/.env nano /opt/apps/outline/docker-compose.yml ``` 3. Deploy the service: ```bash theme={null} cd /opt/apps/outline docker compose up -d ``` 4. Verify the services are running: ```bash theme={null} docker compose ps ``` 5. Access Outline at `https://wiki.trymondo.com` and sign in using your Auth0 credentials. ## Auth0 Configuration Before deploying Outline, you need to configure Auth0: 1. Create a new application in Auth0 2. Set the application type to "Regular Web Application" 3. Configure the following URLs: * Allowed Callback URLs: `https://wiki.trymondo.com/auth/oidc.callback` * Allowed Logout URLs: `https://wiki.trymondo.com` 4. Note the Client ID and Client Secret for the `.env` file ## Traefik Integration Outline is configured with the following Traefik settings: * **Host Rule**: `wiki.trymondo.com` * **Entrypoint**: websecure (HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 3000 * **Middleware**: secureHeaders for enhanced security ## Configuration Highlights ### File Storage Outline is configured to use local file storage with the following settings: * **Storage Directory**: `/opt/outline/storage` * **Maximum Upload Size**: 25MB (26,214,400 bytes) * **Storage Path**: Mounted to `./data/uploads` on the host ### Database Connection Pool PostgreSQL connection pooling is configured for optimal performance: * **Minimum Connections**: 2 * **Maximum Connections**: 10 ## Maintenance ### Backup Strategy Back up Outline regularly using the following steps: ```bash theme={null} # Stop the containers cd /opt/apps/outline docker compose stop # Backup the database docker compose exec postgres pg_dump -U outline -d outline > outline_backup_$(date +%Y%m%d).sql # Backup uploaded files tar -czf outline_uploads_$(date +%Y%m%d).tar.gz -C /opt/apps/outline/data uploads # Restart the containers docker compose start ``` !!! note Consider scheduling regular backups using cron and storing them offsite. ### Updates To update Outline: 1. Update the image tag in `docker-compose.yml` 2. Apply the update: ```bash theme={null} cd /opt/apps/outline docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs ``` Always back up your data before updating Outline to a new version. ## Troubleshooting ### Auth0 Connection Issues If you can't sign in with Auth0: 1. Verify Auth0 configuration: * Check the callback URL in Auth0 * Verify Client ID and Secret in `.env` 2. Check Outline logs for auth errors: ```bash theme={null} docker compose logs outline | grep -i "auth" ``` ### Database Connection Problems If Outline can't connect to the database: 1. Verify PostgreSQL container is running: ```bash theme={null} docker compose ps postgres ``` 2. Check database logs: ```bash theme={null} docker compose logs postgres ``` 3. Test database connection: ```bash theme={null} docker compose exec postgres psql -U outline -c "SELECT 1;" ``` ### File Upload Issues If file uploads aren't working: 1. Check permissions on the upload directory: ```bash theme={null} ls -la /opt/apps/outline/data/uploads ``` 2. Verify the user ID matches what's in the `docker-compose.yml` file: ```bash theme={null} id -u outline ``` 3. Check for storage-related errors in logs: ```bash theme={null} docker compose logs outline | grep -i "storage" ``` ## User Management ### Adding Users Outline uses Auth0 for authentication, so users are managed through Auth0: 1. Users must be able to sign in through Auth0 2. On first login, users will be created in Outline 3. Admin users can promote others to admin through the Outline UI ### Setting Up Teams To organize users into teams: 1. Sign in as an admin 2. Go to Settings > Teams 3. Create new teams and invite members by email ## Document Structure Outline uses a hierarchical document structure: * **Collections**: Top-level containers for related documents * **Documents**: Individual wiki pages within collections * **Sections**: Hierarchical organization within documents ## Integration Examples ### Slack Integration To integrate Outline with Slack: 1. Go to Settings > Integrations 2. Click on Slack and follow the configuration steps 3. Users will be able to share and search Outline documents directly from Slack ### API Usage Outline provides a REST API for integration with other systems: 1. Generate an API token in Settings > API Tokens 2. Use the token to authenticate API requests: ```bash theme={null} curl -H "Authorization: Bearer YOUR_API_TOKEN" https://wiki.trymondo.com/api/documents ``` ## Additional Resources * [Official Outline Documentation](https://docs.getoutline.com/) * [Outline GitHub Repository](https://github.com/outline/outline) * [Auth0 Documentation](https://auth0.com/docs/) * [PostgreSQL Documentation](https://www.postgresql.org/docs/) * [Traefik Documentation](https://doc.traefik.io/traefik/) ## Best Practices * Enable regular backups of database and uploads * Monitor disk space usage on the uploads directory * Update Outline regularly for security patches * Use document templates for consistent content * Organize collections by team or project area # Changelog Source: https://docs.trymondo.com/mops/changelog This project is still in heavy development, but we will post updates here. ### March 2024 This is the initial update. MOPS is live in alpha stage at dash.trymondo.com # null Source: https://docs.trymondo.com/mops/devops/diun ## Overview Diun (Docker Image Update Notifier) is a service that automatically monitors Docker container images and sends notifications when updates are detected. This document covers the deployment and configuration of Diun using Docker Compose. ## Service Details | Component | Value | | -------------------- | -------------------------- | | Image | crazymax/diun:4.29.0 | | Container Name | diun | | Volume | diun-data | | Watch Schedule | Every hour (0 \* \* \* \*) | | Notification Channel | Discord | | Time Zone | America/Denver | ## Architecture Diun operates as a standalone container with the following connections: ``` ┌─────────────┐ │ Discord │ └─────────────┘ ▲ │ Notifications │ ┌─────────────┐ ┌─────────────┐ │ Diun │───▶│Docker Socket│ └─────────────┘ └─────────────┘ │ ▼ ┌─────────────┐ │Persistent DB│ └─────────────┘ ``` * **Docker Socket**: Diun monitors running containers via the Docker socket * **Persistent Data**: State is maintained across restarts using a Docker volume * **Notifications**: Updates are sent to Discord via webhooks ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Discord server with webhook permissions (for notifications) * Running containers with the `diun.enable=true` label ## Environment Variables Create a `.env` file with the following variable: ``` DIUN_DISCORD_WEBHOOK=https://discord.com/api/webhooks/your-webhook-url ``` Never commit the `.env` file to version control. Store your webhook URL securely in a password manager. ## Deployment Configuration ### Docker Compose File ```yaml theme={null} services: diun: image: crazymax/diun:4.29.0 container_name: diun command: serve volumes: - 'diun-data:/data' - '/var/run/docker.sock:/var/run/docker.sock' environment: - 'TZ=America/Denver' - 'LOG_LEVEL=info' - 'LOG_JSON=false' - 'DIUN_WATCH_WORKERS=20' - 'DIUN_WATCH_SCHEDULE=0 * * * *' - 'DIUN_WATCH_JITTER=30s' - 'DIUN_PROVIDERS_DOCKER=true' - 'DIUN_NOTIF_DISCORD_WEBHOOKURL=${DIUN_DISCORD_WEBHOOK}' - 'DIUN_NOTIF_DISCORD_MENTIONS=@here' restart: always volumes: diun-data: ``` ## Deployment Instructions 1. Create the deployment directory: ```bash theme={null} mkdir -p /opt/apps/diun ``` 2. Create the `docker-compose.yml` and `.env` files: ```bash theme={null} nano /opt/apps/diun/docker-compose.yml nano /opt/apps/diun/.env ``` 3. Deploy the service: ```bash theme={null} cd /opt/apps/diun docker compose up -d ``` 4. Verify the service is running: ```bash theme={null} docker compose ps docker compose logs ``` ## Configuration Highlights ### Watch Settings Diun is configured with the following watch parameters: * **Schedule**: Every hour (`0 * * * *` cron expression) * **Workers**: 20 concurrent image checks * **Jitter**: 30-second random delay to avoid API rate limits ### Notification Setup Notifications are configured to: * Send to Discord via webhook * Mention `@here` for visibility * Include detailed image update information ## Enabling Monitoring for Containers To monitor a container for updates, add the following label to its configuration: ```yaml theme={null} labels: - 'diun.enable=true' ``` ### Advanced Container Monitoring You can add additional labels to customize monitoring: ```yaml theme={null} labels: - 'diun.enable=true' # Enable monitoring - 'diun.watch_repo=true' # Watch all tags of this image - 'diun.max_tags=5' # Limit number of tags to watch - 'diun.include_tags=^1\\..*,^2\\..*$' # Only include specific tag patterns - 'diun.exclude_tags=.*-alpha.*' # Exclude specific tag patterns ``` ## Example: Monitoring Multiple Services Here's an example of enabling Diun monitoring for several containers: ```yaml theme={null} # Gitea configuration services: server: image: gitea/gitea:1.23.7-rootless labels: - 'diun.enable=true' db: image: postgres:17.4 labels: - 'diun.enable=true' ``` ## Maintenance ### Backup Strategy Back up Diun's data regularly: ```bash theme={null} # Option 1: Use Restic/Backrest for the volume # Include /var/lib/docker/volumes/diun_diun-data in your backup paths # Option 2: Manual backup docker compose stop tar -czf diun-backup-$(date +%Y%m%d).tar.gz -C /var/lib/docker/volumes/diun_diun-data . docker compose start ``` ### Updates To update Diun: 1. Update the image tag in `docker-compose.yml` 2. Apply the update: ```bash theme={null} docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs ``` ## Troubleshooting ### No Notifications If you're not receiving notifications: 1. Verify Discord webhook URL is correct: ```bash theme={null} docker compose logs diun | grep -i "discord" ``` 2. Check if Diun is running on schedule: ```bash theme={null} docker compose logs diun | grep -i "cron" ``` 3. Test the webhook manually: ```bash theme={null} curl -X POST -H "Content-Type: application/json" \ -d '{"content": "Testing webhook"}' \ $DIUN_DISCORD_WEBHOOK ``` ### No Images Being Monitored If no images are being monitored: 1. Verify Docker socket access: ```bash theme={null} docker compose exec diun ls -la /var/run/docker.sock ``` 2. Check container discovery logs: ```bash theme={null} docker compose logs diun | grep -i "docker provider" ``` 3. Ensure containers have the proper `diun.enable=true` label ## Image Update Triggers Diun identifies image updates by: 1. **Tag Changes**: When an image with a specific tag is updated 2. **New Tags**: When configured to watch repositories for new tags 3. **Manifest Changes**: When the image digest changes, even if the tag remains the same ## Manual Update Check To trigger an immediate update check: ```bash theme={null} docker compose exec diun diun run ``` ## Security Considerations * **Docker Socket**: Diun has access to the Docker socket, granting it significant privileges * **Discord Webhook**: Keep your webhook URL confidential to prevent unauthorized notifications * **Image Policies**: Consider using `diun.include_tags` to only monitor production tags ## Additional Resources * [Official Diun Documentation](https://crazymax.dev/diun/) * [Diun GitHub Repository](https://github.com/crazy-max/diun) * [Cron Expression Format](https://en.wikipedia.org/wiki/Cron#CRON_expression) ## Integration Examples ### Complete Stack Example Add Diun labels to your existing infrastructure: ```yaml theme={null} # Example Traefik integration services: traefik: image: traefik:v3.3.5 labels: - 'diun.enable=true' - 'diun.include_tags=^v3\\..*$' postgres: image: postgres:17 labels: - 'diun.enable=true' - 'diun.watch_repo=false' # Only watch the specific tag ``` # null Source: https://docs.trymondo.com/mops/devops/gitea ## Overview Gitea is a lightweight, self-hosted Git service that provides repository management, issue tracking, and CI/CD integration through Woodpecker CI. This document covers the deployment and configuration of Gitea using Docker Compose with Traefik as a reverse proxy. ## Service Details | Component | Value | | ---------- | ---------------------------------------------------- | | URL | [https://git.trymondo.com](https://git.trymondo.com) | | Main Image | gitea/gitea:1.23.7-rootless | | Database | PostgreSQL 17.4 | | Containers | gitea, gitea-db | | SSH Port | 2222 (via Traefik) | | Networks | gitea-net, traefik-net | | Time Zone | America/Denver | ## Architecture The deployment consists of: 1. **Gitea Server**: The main application container running the Git service 2. **PostgreSQL Database**: Persistent storage for all Gitea data 3. **Traefik Integration**: Handles routing, SSL termination, and SSH proxying ``` ┌─────────────┐ │ Traefik │ └─────────────┘ ↑ ↑ HTTP/HTTPS ┌─┘ └─┐ SSH │ │ ┌──────────────┐ ┌─────────────┐ │ Gitea Server │◄───┤ Gitea SSH │ └──────────────┘ └─────────────┘ ▲ │ ┌──────────────┐ │ PostgreSQL │ └──────────────┘ ``` ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External networks: `gitea-net` and `traefik-net` * SSH entrypoint configured in Traefik * DNS configured for `git.trymondo.com` ## Deployment Configuration ### Environment Variables Create a `.env` file with the following variables: ``` GITEA_DB_PASSWORD=secure_password_here POSTGRES_PASSWORD=secure_password_here ``` Never commit the `.env` file to version control. Store passwords securely in a password manager. ### Docker Compose File ```yaml theme={null} services: server: image: gitea/gitea:1.23.7-rootless container_name: gitea restart: unless-stopped volumes: - gitea-data:/var/lib/gitea - gitea-config:/etc/gitea environment: - TZ=America/Denver - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=db:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=gitea - GITEA__database__PASSWD=${GITEA_DB_PASSWORD} depends_on: - db networks: - gitea-net - traefik-net labels: - traefik.enable=true - traefik.http.routers.gitea.rule=Host(`git.trymondo.com`) - traefik.http.routers.gitea.entrypoints=websecure - traefik.http.routers.gitea.tls.certresolver=production - traefik.http.services.gitea.loadbalancer.server.port=3000 - traefik.tcp.routers.gitea-ssh.rule=HostSNI(`*`) - traefik.tcp.routers.gitea-ssh.entrypoints=ssh - traefik.tcp.routers.gitea-ssh.service=gitea-ssh - traefik.tcp.services.gitea-ssh.loadbalancer.server.port=2222 - 'diun.enable=true' db: image: postgres:17.4 container_name: gitea-db restart: unless-stopped environment: - TZ=America/Denver - POSTGRES_DB=gitea - POSTGRES_USER=gitea - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} volumes: - gitea-db-data:/var/lib/postgresql/data networks: - gitea-net labels: - 'diun.enable=true' volumes: gitea-data: gitea-config: gitea-db-data: networks: gitea-net: external: true traefik-net: external: true ``` ## Network Configuration Before deployment, ensure the required networks exist: ```bash theme={null} # Create external networks if they don't exist docker network create gitea-net docker network create traefik-net ``` ## Deployment Instructions 1. Create the deployment directory: ```bash theme={null} mkdir -p /opt/apps/gitea ``` 2. Create the `docker-compose.yml` and `.env` files: ```bash theme={null} nano /opt/apps/gitea/docker-compose.yml nano /opt/apps/gitea/.env ``` 3. Deploy the service: ```bash theme={null} cd /opt/apps/gitea docker compose up -d ``` 4. Verify the service is running: ```bash theme={null} docker compose ps ``` ## Traefik Integration Details ### HTTP Routing Gitea's web interface is available through HTTPS: * **Host Rule**: `git.trymondo.com` * **Entrypoint**: websecure (HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 3000 ### SSH Routing Git SSH operations are handled through Traefik's TCP router: * **Rule**: HostSNI(`*`) - accepts all hostnames for SSH * **Entrypoint**: ssh (TCP port typically 2222) * **Service**: gitea-ssh * **Backend Port**: 2222 Users will need to configure their Git client to use port 2222 for SSH operations: `git clone ssh://git@git.trymondo.com:2222/username/repo.git` ## Initial Configuration After deploying Gitea, complete the setup through the web interface: 1. Access `https://git.trymondo.com` in your browser 2. You'll be redirected to the installation page 3. Configure the following settings: ### Database Settings * **Database Type**: PostgreSQL (pre-configured) * **Host**: db:5432 (pre-configured) * **Username**: gitea (pre-configured) * **Password**: \[value from .env file] (pre-configured) * **Database Name**: gitea (pre-configured) ### Application General Settings * **Site Title**: GitMondo (recommended) * **Repository Root Path**: /var/lib/gitea/repositories (default) * **Git LFS Root Path**: /var/lib/gitea/lfs (default) * **Run As Username**: git (default) * **SSH Server Domain**: git.trymondo.com * **SSH Server Port**: 2222 * **Gitea HTTP Listen Port**: 3000 (default) * **Gitea Base URL**: [https://git.trymondo.com/](https://git.trymondo.com/) * **Log Path**: /var/lib/gitea/log (default) ### Email Settings (Optional) * **SMTP Host**: smtp.mailersend.net * **SMTP Port**: 587 * **From Email**: [info@trymondo.com](mailto:info@trymondo.com) * **SMTP Username**: \[your SMTP username] * **SMTP Password**: \[your SMTP password] ### Administrator Account * Create an initial administrator account with secure credentials ## Maintenance ### Backup Strategy Back up Gitea regularly using the following steps: 1. Stop the Gitea container (keep the database running): ```bash theme={null} docker compose stop server ``` 2. Back up volumes: ```bash theme={null} # Use Restic or another backup tool to back up these volumes: # - gitea-data # - gitea-config # - gitea-db-data ``` 3. Restart Gitea: ```bash theme={null} docker compose start server ``` Consider using Backrest to automate regular backups of Gitea's volumes. ### Updates To update Gitea: 1. Update the image tag in `docker-compose.yml` 2. Apply the update: ```bash theme={null} docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs -f server ``` ## Troubleshooting ### Database Connection Issues If Gitea can't connect to the database: 1. Verify PostgreSQL container is running: ```bash theme={null} docker compose ps db ``` 2. Check database logs: ```bash theme={null} docker compose logs db ``` 3. Test database connection: ```bash theme={null} docker compose exec db psql -U gitea -d gitea -c "SELECT 1;" ``` ### SSH Connection Problems If Git SSH operations fail: 1. Verify Traefik is properly routing SSH traffic: ```bash theme={null} # Check if port 2222 is open telnet git.trymondo.com 2222 ``` 2. Check Gitea's SSH settings: ```bash theme={null} # View SSH configuration docker compose exec server cat /etc/gitea/app.ini | grep SSH ``` 3. Verify user's SSH configuration: ```bash theme={null} # Example ~/.ssh/config entry for users Host git.trymondo.com Port 2222 User git ``` ## Monitoring Gitea and its database have Diun labels for container update monitoring: ```yaml theme={null} labels: - 'diun.enable=true' ``` ## Additional Resources * [Official Gitea Documentation](https://docs.gitea.com/) * [Gitea Container Documentation](https://docs.gitea.com/installation/install-with-docker) * [PostgreSQL Documentation](https://www.postgresql.org/docs/) * [Traefik TCP Routing Documentation](https://doc.traefik.io/traefik/routing/services/#configuring-tcp-services) ## Integration with CI/CD For CI/CD integration with Woodpecker CI, see the DevOps Stack documentation. # null Source: https://docs.trymondo.com/mops/devops/woodpecker ## Overview Woodpecker CI is a lightweight, cloud-native continuous integration and deployment system built on Docker. This document covers the deployment and configuration of Woodpecker CI using Docker Compose with Traefik as a reverse proxy. ## Service Details | Component | Value | | -------------- | -------------------------------------------------- | | URL | [https://ci.trymondo.com](https://ci.trymondo.com) | | Server Image | woodpeckerci/woodpecker-server:v3.5.2 | | Agent Image | woodpeckerci/woodpecker-agent:v3.5.2 | | Database | PostgreSQL 17 | | Services | woodpecker-server, woodpecker-agent, woodpecker-db | | Networks | woodpecker-net, traefik-net | | Authentication | GitHub OAuth | ## Architecture The deployment consists of three main components: 1. **Woodpecker Server**: The core service that manages the UI, API, and orchestrates CI jobs 2. **Woodpecker Agent**: Executes CI jobs in containers 3. **PostgreSQL Database**: Stores all Woodpecker CI data ``` ┌─────────────┐ │ Traefik │ └─────────────┘ ↑ │ HTTP/HTTPS ↓ ┌─────────────────────┐ │ Woodpecker Server │ └─────────────────────┘ ↑ ↑ gRPC (9000) │ │ Database ↓ ↓ ┌───────────────┐ ┌────────────┐ │ Woodpecker │ │ PostgreSQL │ │ Agent │ │ │ └───────────────┘ └────────────┘ ↑ │ ┌──────────────┐ │ Docker API │ └──────────────┘ ``` ## Prerequisites * Docker Engine (24.0+) * Docker Compose v2 * Traefik reverse proxy configured and running * External networks: `woodpecker-net` and `traefik-net` * GitHub OAuth application * DNS configured for `ci.trymondo.com` ## Configuration Preparation ### GitHub OAuth Setup 1. Create a GitHub OAuth application at [https://github.com/settings/applications/new](https://github.com/settings/applications/new) 2. Set the callback URL to `https://ci.trymondo.com/login` 3. Note the Client ID and Client Secret for your `.env` file ### Environment Variables Create a `.env` file with the following variables: ```env theme={null} # Woodpecker Configuration WOODPECKER_HOST=https://ci.trymondo.com WOODPECKER_OPEN=true WOODPECKER_GITHUB_CLIENT=your_github_client_id WOODPECKER_GITHUB_SECRET=your_github_client_secret WOODPECKER_AGENT_SECRET=generate_a_secure_random_string WOODPECKER_ADMIN=github_username # Database Configuration POSTGRES_PASSWORD=secure_postgres_password ``` Generate a secure, random string for WOODPECKER\_AGENT\_SECRET. This is used to authenticate agents with the server. You can generate a secure random string with: ```bash theme={null} openssl rand -hex 32 ``` ## Deployment Configuration ### Docker Compose File ```yaml theme={null} services: woodpecker-server: image: woodpeckerci/woodpecker-server:v3.5.2 container_name: woodpecker-server restart: unless-stopped expose: - '8000' - '9000' volumes: - woodpecker-server-data:/var/lib/woodpecker environment: - WOODPECKER_OPEN=${WOODPECKER_OPEN:-true} - WOODPECKER_HOST=${WOODPECKER_HOST?Variable WOODPECKER_HOST is not set} - WOODPECKER_GITHUB=true - WOODPECKER_GITHUB_CLIENT=${WOODPECKER_GITHUB_CLIENT?Variable WOODPECKER_GITHUB_CLIENT is not set} - WOODPECKER_GITHUB_SECRET=${WOODPECKER_GITHUB_SECRET?Variable WOODPECKER_GITHUB_SECRET is not set} - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET?Variable WOODPECKER_AGENT_SECRET is not set} - WOODPECKER_DATABASE_DRIVER=postgres - WOODPECKER_DATABASE_DATASOURCE=postgres://woodpecker:${POSTGRES_PASSWORD?Variable POSTGRES_PASSWORD is not set}@woodpecker-db:5432/woodpecker?sslmode=disable - WOODPECKER_GITHUB_URL=https://github.com - WOODPECKER_ADMIN=${WOODPECKER_ADMIN?Variable WOODPECKER_ADMIN is not set} networks: - woodpecker-net - traefik-net labels: - traefik.enable=true - traefik.docker.network=traefik-net - traefik.http.services.woodpecker.loadbalancer.server.port=8000 - traefik.http.routers.woodpecker-secure.rule=Host(`ci.trymondo.com`) - traefik.http.routers.woodpecker-secure.entrypoints=websecure - traefik.http.routers.woodpecker-secure.service=woodpecker - traefik.http.routers.woodpecker-secure.tls=true - traefik.http.routers.woodpecker-secure.tls.certresolver=production - traefik.http.middlewares.woodpecker-redirect.redirectscheme.scheme=https - traefik.http.middlewares.woodpecker-redirect.redirectscheme.permanent=true - traefik.http.routers.woodpecker-http.rule=Host(`ci.trymondo.com`) - traefik.http.routers.woodpecker-http.entrypoints=web - traefik.http.routers.woodpecker-http.service=woodpecker - traefik.http.routers.woodpecker-http.middlewares=woodpecker-redirect@docker woodpecker-agent: image: woodpeckerci/woodpecker-agent:v3.5.2 container_name: woodpecker-agent restart: unless-stopped depends_on: - woodpecker-server volumes: - /var/run/docker.sock:/var/run/docker.sock:rw environment: - WOODPECKER_SERVER=woodpecker-server:9000 - WOODPECKER_GRPC_SECURE=false - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET?Variable WOODPECKER_AGENT_SECRET is not set} networks: - woodpecker-net woodpecker-db: image: postgres:17 container_name: woodpecker-db restart: unless-stopped environment: - POSTGRES_USER=woodpecker - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=woodpecker volumes: - woodpecker-db-data:/var/lib/postgresql/data networks: - woodpecker-net volumes: woodpecker-server-data: woodpecker-db-data: networks: woodpecker-net: external: true traefik-net: external: true ``` ## Network Configuration Before deployment, ensure the required networks exist: ```bash theme={null} docker network create woodpecker-net docker network create traefik-net ``` ## Deployment Instructions 1. Create the deployment directory: ```bash theme={null} mkdir -p /opt/apps/woodpecker ``` 2. Create the `docker-compose.yml` and `.env` files: ```bash theme={null} nano /opt/apps/woodpecker/docker-compose.yml nano /opt/apps/woodpecker/.env ``` 3. Deploy the service: ```bash theme={null} cd /opt/apps/woodpecker docker compose up -d ``` 4. Verify all services are running: ```bash theme={null} docker compose ps ``` ## Traefik Integration Details The Woodpecker server is configured with the following Traefik settings: * **Host Rule**: `ci.trymondo.com` * **Entrypoints**: websecure (HTTPS on port 443), web (HTTP on port 80 with redirect to HTTPS) * **TLS**: Enabled with production certificate resolver * **Backend Port**: 8000 (Woodpecker Web UI) * **Middleware**: HTTP to HTTPS redirect for enhanced security ## Pipeline Configuration ### Basic .woodpecker.yml Example Create a `.woodpecker.yml` file in the root of your GitHub repository: ```yaml theme={null} pipeline: build: image: node:20 commands: - npm install - npm run build - npm test docker: image: plugins/docker settings: registry: registry.example.com repo: registry.example.com/myapp tags: latest username: from_secret: docker_username password: from_secret: docker_password when: branch: main ``` ### Secrets Management To add secrets to your Woodpecker CI projects: 1. Navigate to your repository in the Woodpecker UI 2. Go to **Settings** > **Secrets** 3. Add required secrets (e.g., `docker_username`, `docker_password`) ## Scaling and Performance ### Additional Agents To scale out CI capacity, you can add more agents: ```yaml theme={null} woodpecker-agent-2: image: woodpeckerci/woodpecker-agent:v3.5.2 container_name: woodpecker-agent-2 restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock:rw environment: - WOODPECKER_SERVER=woodpecker-server:9000 - WOODPECKER_GRPC_SECURE=false - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET} networks: - woodpecker-net ``` ### Resource Constraints For improved stability, consider adding resource constraints: ```yaml theme={null} deploy: resources: limits: cpus: '2.0' memory: 2G ``` ## Maintenance ### Backup Strategy Back up Woodpecker CI regularly: 1. Database backup: ```bash theme={null} docker compose exec woodpecker-db pg_dump -U woodpecker woodpecker > woodpecker_backup_$(date +%Y%m%d).sql ``` 2. Volume backup using Restic/Backrest: * `woodpecker-server-data` (contains server state) * `woodpecker-db-data` (contains database files) ### Updates To update Woodpecker CI: 1. Update the image tags in `docker-compose.yml` 2. Apply the update: ```bash theme={null} docker compose pull docker compose up -d ``` 3. Check logs for any issues: ```bash theme={null} docker compose logs ``` ## Troubleshooting ### Server Startup Issues If the server fails to start: 1. Check environment variables: ```bash theme={null} docker compose logs woodpecker-server | grep "required key" ``` 2. Verify database connection: ```bash theme={null} docker compose logs woodpecker-server | grep "database" ``` ### Agent Connection Problems If agents can't connect to the server: 1. Check agent logs: ```bash theme={null} docker compose logs woodpecker-agent ``` 2. Verify agent secret is consistent between server and agent 3. Check network connectivity between containers: ```bash theme={null} docker compose exec woodpecker-agent ping woodpecker-server ``` ### GitHub Integration Issues If GitHub integration is not working: 1. Verify OAuth callback URL is correctly set to `https://ci.trymondo.com/login` 2. Check GitHub client ID and secret in environment variables 3. Examine server logs for OAuth-related errors: ```bash theme={null} docker compose logs woodpecker-server | grep -i "github" ``` ## Security Considerations * **Agent Secret**: Use a strong, randomly generated secret for agent authentication * **Admin Access**: Limit admin access to specific GitHub usernames * **Docker Socket**: The agent has access to the Docker socket, which grants significant privileges * **HTTPS**: Enforce HTTPS-only access through Traefik * **Network Isolation**: Use separate networks for communication between services ## Additional Resources * [Official Woodpecker CI Documentation](https://woodpecker-ci.org/docs/) * [Woodpecker CI GitHub Repository](https://github.com/woodpecker-ci/woodpecker) * [Traefik Documentation](https://doc.traefik.io/traefik/) * [PostgreSQL Documentation](https://www.postgresql.org/docs/) ## Pipeline Examples ### Node.js Application ```yaml theme={null} pipeline: test: image: node:20 commands: - npm install - npm test ``` ### Docker Build and Push ```yaml theme={null} pipeline: build: image: plugins/docker settings: registry: docker.io repo: myuser/myapp tags: latest username: from_secret: docker_username password: from_secret: docker_password ``` ### Multi-stage Pipeline with Approval ```yaml theme={null} pipeline: test: image: golang:1.21 commands: - go test ./... build: image: golang:1.21 commands: - go build -o myapp deploy: image: plugins/ssh settings: host: production.example.com user: deploy key: from_secret: ssh_key script: - ./deploy.sh when: status: success branch: main approval: approved_by: - admin_user ``` # Overview Source: https://docs.trymondo.com/mops/infrastructure This document defines how to work with MOPS infrastructure across environments (dev, staging, prod) using Docker, Portainer, and Git. It ensures Jordan and Joe operate with the same brain and adhere to expert standards. ## Folder Structure ``` MOPS/ ├── environments/ │ ├── dev/ │ │ ├── n8n/ │ │ │ ├── .env │ │ │ └── docker-compose.yml │ │ └── traefik/ │ ├── staging/ │ │ ├── n8n/ │ │ └── traefik/ │ └── prod/ │ ├── n8n/ │ └── traefik/ ├── shared/ # Reserved for shared future config fragments └── README.md ``` *** ## Stack Naming (Portainer) * Format: `[env]-[service]-stack` * Examples: * `dev-n8n-stack` * `prod-n8n-stack` * `staging-traefik-stack` All container, volume, and network names follow the same prefixing rule. *** ## Environments ### `dev/` * Used for experiments, rapid iteration, test credentials only. * Safe to break. * Only accessible to internal team. ### `staging/` * Used for internal QA. * Should mirror `prod` config and infrastructure 1:1 as closely as possible. * Uses *real integration endpoints* (e.g., SMTP, OAuth), but **not production data**. ### `prod/` * Production-only. * Zero downtime expectation. * Code and config **`must flow from staging`**, not directly from `dev`. *** ## Workflow Summary 1. **`Develop in dev/`** * Work with live containers locally or via Portainer Stack. * Debug, test new features, iterate quickly. 2. **`Promote to staging/`** * Use `rsync` or `git` to copy the working config. * Replace test `.env` values with real sandbox/QA credentials. * Run end-to-end test flows. 3. **`Promote to prod/`** * Only after staging passes. * Tag commit (`v1.2.0-prod`), deploy via CI/CD or Portainer Git Stack. * Document changes and review logs post-deploy. *** ## Secrets Management ### Current State `.env` files are stored in Git — this is **not secure**. ### Immediate Fix * Move `.env` values to Portainer **Secrets** (per environment). * Reference them in `docker-compose.yml` like this: ```yaml theme={null} env_file: - /run/secrets/n8n_api_key ``` ### Near-Future Upgrade Path * Use [dotenv-vault](https://www.dotenv.org/) or \[SOPS + Git-crypt] for OSS secret encryption. * Alternative: GitHub Actions + \[secrets manager] for automated secure injection. *** ## CI/CD Plan ### Goals * Push to `environments/prod/**` requires PR approval and triggers deploy to `prod` * Push to `environments¸/staging/**` triggers deploy to `staging` ### Tool: GitHub Actions ```yaml theme={null} on: push: paths: - 'environments/staging/**' branches: - main jobs: deploy-staging: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Deploy to Staging run: | ssh user@server 'cd /docker && docker compose -f environments/staging/n8n/docker-compose.yml up -d' ``` Add manual approval + backup steps for `prod`. *** ## Backup & Rollback Plan ### For PostgreSQL (n8n, mautic): * Use `pg_dump` and `pg_restore`. * Set up nightly cron-based backup containers. ### For Volumes: * Use \[bind mounts] to make data externally accessible. * Snapshot `/var/lib/docker/volumes` regularly using rsync or Btrfs/ZFS snapshots. *** ## Best Practices * Never deploy to `prod` directly. * Never store `.env` with secrets in Git. * Always test in `staging` before production. * Always prefix stacks/networks/containers with `[env]-[service]`. * Always document new services in their `README.md`. * Avoid floating Docker image tags in `prod` (e.g., use `n8nio/n8n:1.27.1` not `:latest`). *** ## Future Improvements * Central secrets manager * Automated rollback script * Infra diagram / dependency map * Multi-server orchestration (Docker Swarm or K8s) * Terraform/Ansible for provisioning VPSes *** > Questions? Ping Jordan or Joe. Otherwise: build, test, promote. Stay sharp. > git config --global pull.rebase true # Introduction Source: https://docs.trymondo.com/mops/introduction Welcome to the official documentation for **Mondo** – your open platform for modern, privacy-respecting software. To report a bug, visit \[[https://tally.so/r/w8E7Qx](https://tally.so/r/w8E7Qx)] ## 🔍 What You'll Find Here * **Getting Started** – Learn how to install, configure, and deploy Mondo. * **Features** – Explore what makes Mondo powerful and modular. * **Developer Guide** – Dive into APIs, integrations, and advanced workflows. * **FAQ & Troubleshooting** – Common questions, tips, and fixes. *** ## 📦 Quick Start ```bash theme={null} git clone https://github.com/mondosolutions/MOPS.git cd MOPS docker compose up -d ``` Open your browser at [http://localhost:8000](http://localhost:8000) to explore the docs locally. *** ## 📚 Project Overview Mondo is a modular open platform that helps teams build and scale self-hosted infrastructure with: * ⚡️ Rapid deployment via Docker & Traefik * 🔐 Privacy-first approach with no data sent to third parties * 🧩 Easily extensible with open standards * 💬 Active community support *** ## 💬 Join the Conversation * [GitHub Discussions](https://github.com/mondosolutions/MOPS/discussions) * [Submit an Issue](https://github.com/mondosolutions/MOPS/issues) *** ## 👏 Contributing We welcome contributions! Check out our [contribution guide](contributing.md) to get started. *** Get your docs set up locally for easy development Preview your changes before you push to make sure they're perfect Build interactive features and designs to guide your users Check out our showcase of our favorite documentation # null Source: https://docs.trymondo.com/mops/project-overview # Mondo MOPS (Mondo Open Platform Service) **A privacy-first, self-hosted open platform for modern marketing teams and agencies.** ## What This Repo Contains This repository contains the full deployment framework for the MOPS platform, including: * **Core Marketing Services**: Mautic (email marketing), n8n (workflow automation), EspoCRM (customer relationship management), Outline (knowledge base), Cal.com (scheduling) * **Infrastructure Configuration**: Traefik (reverse proxy), Docker Compose files, environment configurations * **Monitoring & Management**: Loki/Grafana (logging), Backrest/Restic (backups), Portainer (container management) * **Authentication & Security**: Authentik (identity provider), secure headers configuration MOPS follows a modular architecture allowing teams to deploy only the services they need while maintaining a consistent management interface. ## Why Use Mondo MOPS? * **100% Self-Hosted, Privacy-Respecting**: Complete control over your marketing data and infrastructure * **Pre-Integrated Tools**: Carefully selected and configured marketing tools that work together seamlessly * **Enterprise-Grade Infrastructure**: Built with Docker, Traefik, and modern DevOps practices for reliability * **Consistent Environments**: Standardized development, staging, and production environments * **Open Source Foundation**: Built on trusted open source technologies with active communities ## Getting Started ### Basic Requirements * Cloud- or Self-Hosted VPS running Ubuntu 24.04 LTS * Docker 24+ and Docker Compose * Domain name with DNS control for subdomain routing * 2GB+ RAM (4GB+ recommended for full stack) * At least 20GB storage space ### Quick Start 1. Clone this repository 2. Configure your environment variables 3. Run the deployment script For complete installation and deployment instructions, see the [Setup Documentation](./docs/setup/README.md). ## Repository Structure ``` MOPS/ ├── docs/ # Documentation ├── environments/ # Environment-specific configurations │ ├── dev/ # Development environment │ ├── staging/ # Staging environment │ └── prod/ # Production environment │ ├── traefik/ # Reverse proxy configuration │ ├── n8n/ # Workflow automation │ ├── mautic/ # Email marketing platform │ ├── espocrm/ # CRM platform │ ├── outline/ # Knowledge base │ └── ... # Other services ├── shared/ # Shared configurations and utilities └── .github/ └── workflows/ # CI/CD pipelines ``` ## Services | Service | Description | URL | | --------- | ---------------------- | ------------------------ | | Traefik | Reverse Proxy & TLS | traefik.trymondo.com | | Mautic | Email Marketing | outreach.trymondo.com | | n8n | Automation Workflows | automations.trymondo.com | | EspoCRM | CRM Platform | crm.trymondo.com | | Outline | Knowledge Base | wiki.trymondo.com | | Portainer | Container Management | portainer.trymondo.com | | Grafana | Observability | grafana.trymondo.com | | Cal.com | Appointment Scheduling | cal.trymondo.com | | Homer | Service Dashboard | dash.trymondo.com | | FilePizza | File Sharing | pizza.trymondo.com | ## Development !!! note MOPS follows standardized naming conventions across environments. See [Naming Conventions](./docs/naming-conventions.md) for details. For development guidelines, contribution workflows, and technical specifications, refer to the [Developer Documentation](./docs/development/README.md). ## License Mondo MOPS is licensed under the MIT License. See [LICENSE](./LICENSE) for details. *** Developed and maintained by \[ # null Source: https://docs.trymondo.com/mops/troubleshooting This page helps you diagnose and resolve common problems with MOPS services. If your issue isn't listed, please reach out to our support team. ## Table of Contents * [Service Down](#service-down) * [Deployment Failures](#deployment-failures) * [Configuration Errors](#configuration-errors) * [Authentication Issues](#authentication-issues) * [Contact Support](#contact-support) *** ## Service Down * Service is not responding * 5xx errors in logs * Health checks failing **Steps to Diagnose:** 1. Check service status with: ```sh theme={null} systemctl status mops-service ``` 2. Review recent logs: ```sh theme={null} journalctl -u mops-service --since "10 minutes ago" ``` 3. Ensure dependencies (database, network) are operational. *** ## Deployment Failures * Incorrect environment variables * Build errors * Insufficient permissions **Steps to Diagnose:** 1. Review deployment logs for errors. 2. Verify all required environment variables are set. 3. Check permissions for deployment user. *** ## Configuration Errors * Service starts but behaves unexpectedly * Error messages about missing config **Steps to Diagnose:** 1. Validate your configuration file syntax. 2. Ensure all required fields are present. 3. Restart the service after changes. *** ## Authentication Issues * Users cannot log in * 401/403 errors **Steps to Diagnose:** 1. Confirm authentication service is running. 2. Check user credentials and permissions. 3. Review authentication logs for errors. *** ## Contact Support If you can't resolve your issue, please [contact support](mailto:techsupport@trymondo.com) with: * A description of the problem * Steps you've tried * Relevant logs or screenshots *** Continually add new troubleshooting topics below as new issues are discovered! # Connect X API Source: https://docs.trymondo.com/posts/connecting-x A step-by-step guide to help you set up your X API credentials in Mondo Posts. # Setting Up Your X API Credentials in Mondo Posts Follow these simple steps to set up your X API credentials in Mondo Posts. This guide is designed for non-technical users, so no prior technical knowledge is required. ## Step 1: Log in to Your X Account 1. Open your web browser and go to the X Developer Portal: [https://developer.x.com](https://developer.x.com). 2. Log in using your X account credentials. ## Step 2: Create a New App 1. Once logged in, navigate to the **Apps** section. 2. Click on the **Create App** button. 3. Fill in the required details for your app (e.g., name, description, and website URL). 4. Save your app by clicking **Create** or **Save**. ## Step 3: Locate Your API Credentials 1. After creating your app, go to the **Keys and Tokens** section of your app. 2. Copy the following credentials: * **API Key** * **API Secret Key** * **Access Token** * **Access Token Secret** ## Step 4: Open Mondo Posts 1. Log in to your Mondo Posts account at [https://posts.trymondo.com](https://posts.trymondo.com). 2. Navigate to the **Settings** section. ## Step 5: Enter Your X API Credentials 1. In the **Settings** section, find the **API Integrations** or **X Integration** option. 2. Paste the credentials you copied earlier into the corresponding fields: * API Key * API Secret Key * Access Token * Access Token Secret 3. Click **Save** or **Connect** to finalize the setup. ## Step 6: Test the Connection 1. Go back to the Mondo Posts dashboard. 2. Create a test post and try publishing it to X. 3. If the post is successfully published, your setup is complete! Congratulations! You’ve successfully set up your X API credentials in Mondo Posts. If you encounter any issues, refer to the Mondo Posts support team for assistance. # Introduction Source: https://docs.trymondo.com/posts/introduction What is Mondo Posts, and why should you use it? Welcome to Mondo Posts, a powerful and intuitive platform designed to simplify your content creation and management process. Whether you're a seasoned writer or just starting out, Mondo Posts provides the tools you need to create, organize, and share your content effortlessly. ## Why Choose Mondo Posts? Mondo Posts is built with flexibility and ease of use in mind. It empowers you to focus on what matters most—your content—while handling the technical complexities behind the scenes. Here’s why you should consider using Mondo Posts: * **Streamlined Workflow**: Create and manage posts with a user-friendly interface that saves you time and effort. * **Customizable**: Tailor the platform to fit your unique needs and preferences. * **Scalable**: Whether you're managing a personal blog or a large-scale publication, Mondo Posts grows with you. * **Seamless Integration**: Easily integrate with other tools and platforms to enhance your content strategy. ## Getting Started Setting up Mondo Posts is quick and straightforward. These docs will guide you through every step of the process, from installation to advanced customization. Here's how to begin: 1. **Installation**: Follow the setup instructions to get Mondo Posts up and running on your system. 2. **Configuration**: Customize your settings to align with your goals and workflow. 3. **Create Your First Post**: Dive in and start creating content using the intuitive editor. 4. **Explore Advanced Features**: Learn about additional tools and integrations to maximize your productivity. Dive into the documentation to unlock the full potential of Mondo Posts and take your content creation to the next level. Let’s get started! # User Management Source: https://docs.trymondo.com/posts/user-management Best practices for managing clients in Mondo Posts. Managing clients effectively involves organizing and overseeing their accounts, content, and interactions. Start by creating individual profiles for each client to keep their information separate and secure. Use scheduling tools to plan and publish content tailored to their needs. Monitor performance metrics to track engagement and adjust strategies as needed. Regular communication and reporting ensure transparency and help maintain strong client relationships. # Workspaces Source: https://docs.trymondo.com/posts/workspaces How the workspaces work in Mondo Posts and how to get started. # Frontend Source: https://docs.trymondo.com/proposals/frontend The weird journey on how the frontend came to be. ## Design The entire point of building our own proposal software was not to escape the endless fees and revenue sharing that most tools force you into, but to also improve the experience. Mondo's proposals were designed around a few basic concepts: 1. Quickly explain the way Mondo does business. 2. Allow for **clients to choose** what services to proceed with 3. See a very clear and concise pricing breakdown of **one-time and recurring charges.** 4. Clear and concise **timeline estimations** 5. Allow for instant **signatures.** 6. Allow for **payment** All of the above, **in one page experience**, making for a great start to a relationship of ease and simplicity at the core of the Mondo experience. While this is nice and all, we needed to also tie this into utilizing AI to auto-generate proposals by supplemening real-time data that was highly precise to current trends, tools, and analysis. So we had to build in ProposalGen AI. ## Automatic Proposal Generator (supplemented by humans) As Mondo has scaled over the years, the need to build processes around the proposal generation process was a major thorn in our side. This is due to the lack of overall strategic knowledge and know-how of incoming staff to grasp how proposals needed to be priced and pitched. In marketing, we are not always just selling a package of services that are predictable. Most agencies attempt to solve this to skirt around having to solve the proposal problem, but the industry moves to fast to keep services bundled in this manner. In our experience this leads to stagnant, ineffective service offerings that are really only artificially there to benefit the agencies processes and hiring. **The client shouldn't be the victim of this** So what is our solution? Leverage AI with a sliding scale of pricing we have set as a median to each business size and industry. Traditionally, this would be tons of work for a human to work out. By combining the automation and hyper-accurate results of ai, analysis of the client, their industry, their budget, their geo... a human alone would almost never get a proposal to be this accurate. So this works out great; a proposal that benefits both parties, the speed and near elimination of the need to hash over service offerings before even showing it to a potential client, and it **scales**. After many iterations of planning, and resisting the urge to just sign up for the latest paid "solution", we decided that there would always need to be a human touch. Of course. So we introduced a section at the top of all our proposals where a Mondo strategist would provide a video recording of a walkthrough of the proposal to clearly explain what is needed and to engage the customer in iterating on the proposal if necessary. This engagement with the client makes them feel like they are more in-charge than that of the normal agency experience. **This is what we were after.** So here is the flow: 1. Intake form requires many metrics to be gathered on the business through the human sales funnel at Mondo. 2. This data is then split into a marketing analytics agent that goes into very deep research of the businesses' online presence. Content, SEO, website aesthetics, followers, domain authority, etc. 3. Contact and business data is sent to a data enrichment service to gather as much information on the business as possible. Sometimes validating and sometimes not the accuracy of the data given to the salesperson at Mondo. Which helps us be realistic with the client. 4. Data from both is parsed into a problem solving agent that considers all solutions for the business and matches it to a service set at Mondo and possibly even services that Mondo doesn't offer. This is all provided to the client. 5. This is then combined again and parsed into a prompt for pricing. This agent has access to our master pricing list to ensure consideration of our absolute bottom-dollar sale and where the industry norms are. (This allows us freedom to discount services in hopes to persuade the company to invest more into their growth long term) 6. At last, we combine all of this data into a page generating AI that generates static pages and displays them on proposals.trymondo.com 7. Before showing the client the proposal goes through Discord channels to be approved/disapproved. Upon approval, it request a video link to inject into the top of the proposal. 8. Upon decline, it goes back to the pricing engine that iterates upon the changes requested on the proposal and loops this approval process until complete. In the end, the client drastically benefits from the extra research on their business, gives them the best price possible, and Mondo hopefully gets a lifelong customer. Kaboom! Win win. # HTML Generator Source: https://docs.trymondo.com/proposals/htmlgenerator This agent takes the proposal and generates an HTML file thaty is hosted on proposals.trymondo.com # Introduction Source: https://docs.trymondo.com/proposals/introduction This is the introduction to the proposal experience at proposals.trymondo.com # Building a proposal experience like no other. A modern, visually striking landing page for customers to review, select, and purchase proposals, including contract signature and Stripe checkout. ## Features * **View and select proposal options** (with prices) * **Dynamic total calculation** (one-time and subscription charges separated) * **All options pre-selected** on page load for user convenience * **Sticky totals section**: Totals remain visible and become sticky at the bottom on scroll * **Interactive process timeline**: Visual guide from Pick Options → Sign Agreement → Pay → Success 🚀 * **Estimated Timelines panel**: Shows how long each selected service will take (placeholders, ready for Supabase data) * **Digital contract signature**: User must sign before payment * **Confetti celebration**: Confetti flies across the screen when the contract is signed * **Captivating payment button**: Green, full-width, animated, and only enabled after signature (with lawyer tooltip if not signed) * **Stripe Checkout integration** * **Supabase for data storage** * **Fully responsive UI**: Optimized for mobile and desktop * **Dark/light mode** * **Modern gradients and alternating black/white sections** ## Tech Stack * Next.js (React) * Tailwind CSS * Supabase * Stripe * canvas-confetti (for signature celebration) ## Getting Started 1. `npm install` 2. Set up `.env.local` with Supabase and Stripe keys 3. `npm run dev` ### Logo Customization * Replace `/public/mondo-white.svg` with your own logo (SVG/PNG/JPG) and update the `` in `pages/index.js` if needed. ### Confetti Effect * The confetti animation on contract signature uses [`canvas-confetti`](https://www.npmjs.com/package/canvas-confetti). This is installed automatically with `npm install`. ## Deployment Ready for Ubuntu 24.04 VPS. See deployment instructions in this README after setup. ## Usage Guidance * **Select/deselect services**: All are checked by default; uncheck what you don't need. * **Estimated timelines**: Shown for each selected service. * **Sign the contract**: Enter your name and sign to unlock payment. * **Proceed to payment**: Button becomes active after signing. If not signed, a tooltip explains why. * **Celebrate!**: Confetti will fly when you sign the contract. # Marketing Analysis Agent Source: https://docs.trymondo.com/proposals/marketingagent A description of the Gumloop flows are all intertwined to make the system work. \#The following is the promport for the AI agent that will analyze the form data and provide a structured output for the marketing proposal. ```markdown theme={null} You are a senior marketing strategist AI responsible for analyzing client information submitted via a sales intake form. Your task is to provide a clear, actionable brief on **only the marketing services that will directly benefit this business**, while aligning recommendations to their stated goals, challenges, and industry context. Your output will be used by another AI agent to generate a proposal, so consistency, clarity, and accuracy are critical. --- #### Context You will be passed structured form data that includes: - Business details (name, industry, size, region, etc.) - Marketing goals (lead generation, social growth, etc.) - Challenges (competition, growth limitations, niche issues) - Service preferences (ads, website, SEO, etc.) - Specific requests (quote formats, human ideas, transcript uploads) - Optional competitor data - Additional comments from sales reps --- **
will be injected here in plain text format.** {combined_text__NODE_ID__:fVCafeJyusfLVYaaJUDo2Z} --- #### Your Job 1. **Interpret and enrich the form data.**      - Validate each goal and challenge.    - Use context from industry norms, SEMrush audit data, and SEO best practices.    - If the transcript or competitor list is missing or weak, make logical inferences where necessary but flag these assumptions clearly. 2. **Assign all validated, relevant services** into these categories ONLY (even if a category ends up empty):    - Graphic Design      - Web Development and Hosting      - Social Media      - Content Creation      - Photography Services      - Videography Services      - Copywriting Services      - Advertising      - Paid Ads      - Printing Goods      - Newsletters      - SEO      - Reviews & Listings      - Physical Signage      - *Other (only for special requests from the form)* 3. **Provide reasoning for each included category**.      - Tie each service recommendation to a business goal or challenge.    - Avoid generic statements. Be specific and strategic.    - If a category is excluded, say: “Excluded: [Category] – Not relevant to current goals or stage.” 4. **Omit these from your output**:    - Pricing (another agent will handle it)    - Formatting elements (e.g., headers, fonts)    - Any commentary or conversational filler    - Any services/products that the client *already offers* themselves (SaaS, etc.) 5. **If the client offers overlapping services**, recommend a partnership strategy:    - White label opportunities    - Referral strategies    - Cross-branding potential 6. **If competitors are listed**, pass along:    - A basic competitor analysis with strengths, weaknesses, and marketing gaps.    - A short summary of how your proposed services will outperform them. 7. **Assume a modest marketing budget** unless otherwise specified.    - Use national averages to suggest effort levels (e.g., "estimated 10–20 hours", "typical project range"). 8. **Your Output Format Must Be:** [Category] • [Service Recommendation] • [Justification] • [Effort level or scope, using national averages] • [Mention YES, if this is a service that was explicitly mentioned in the form, this is to be a priority service in the proposal in order to honor the sales person’s word of getting prices to the client.] … [Category] • Excluded – Not relevant to goals or context --- Respond ONLY with the structured output as described above. This output will be passed directly into a formatting and pricing AI agent, so keep it clean and modular. Begin. ``` # PDF Generator Source: https://docs.trymondo.com/proposals/pdfgenerator This agent takes the proposal and generates a PDF that can be sent to the client. # Pricing Agent Source: https://docs.trymondo.com/proposals/pricingagent This agent takes structured data from the marketing agent and generates a list of prices that can be used in the proposal. ``` You are the “PROBLEM SOLVER” — a proposal-generating AI assistant responsible for turning structured marketing recommendations into a polished, client-facing proposal document. You are not a copywriter or strategist. Your role is to format, organize, and apply pricing to services based on an existing list of approved recommendations. --- You will receive: {response__NODE_ID__:hCoopDJNRXecLiSR351UTr} (This contains categorized services with descriptions and effort levels.) --- YOUR OUTPUT MUST FOLLOW THIS STRUCTURE (DO NOT DEVIATE): 1. Title (H1) • Example: “Your Proposal from Mondo” 2. Prepared For Section • Format: Prepared for: [Insert Company Name] Date: [Insert Today’s Date] 3. Introduction (H2) • 2–3 friendly, on-brand sentences about what’s inside. • Welcome tone, fun but professional. 4. Scope of Work (H2) • Bullet summary of value and deliverables • Focus on clarity and benefit 5. Recommended Services (H2) • Bullet list of services, no pricing here • Each bullet should reflect 1 clear offer 6. Pricing (H2) • Break down pricing by category • Use line-item format • Tag each price as “One-Time” or “Monthly” • Include: - Grand Total of One-Time Fees - Grand Total of Monthly Services - Note: “10% discount available for annual prepay on monthly services” 7. Project Timeline (H2) • 2–3 sentence overview of expected timeline or bullets (e.g. “2 weeks for landing page design”) 8. Terms & Conditions (H2) • Numbered list with 5 core policies: 1. 50% deposit required to begin work 2. Remaining balance due upon final delivery 3. Revisions included within scope unless otherwise noted 4. Additional work beyond scope is billed at standard hourly rates 5. Proposal valid for 30 days from the date of issue 9. Next Steps (H2) • Step-by-step client instructions (1–4) for how to move forward • Example: 1. Approve this proposal → 2. Pay deposit → etc. 10. Signature & Approval (H2) • Leave space for signature and date 11. Bonus Insights (H2) • Include 2–4 bullets with helpful insights, ideas, SEO notes, or advantages over competitors --- STYLE RULES Tone: • Creative, friendly, fun • Sound like an agency rep who already knows the client • Avoid AI references or robotic phrasing Formatting: • Font: Arial • Title: 20pt, bold, centered • Subheadings: 16pt, bold, left-aligned • Body & bullets: 12pt, regular, left-aligned • Line spacing: 1.5x • Margins: 1 inch all sides • Colors: - Title: #000000 - Subheadings: #333333 - Body text: #000000 --- PRICING RULES Use the official price sheet to assign each service a price. If multiple options are possible, choose the **most contextually appropriate tier.** Add notes if assumptions are made due to limited detail. Round to whole dollars. Never guess prices — use only available pricing data. Do NOT mention pricing strategy, source data, or internal logic. The final output should **feel like a client-ready PDF** with clean, confident numbers and bullet points. --- Begin formatting the proposal now using the information provided from the strategist agent. --- ``` # Database Source: https://docs.trymondo.com/proposals/purpose-supabase What is the role of Supabase in all of this? # Functions Source: https://docs.trymondo.com/proposals/supabase-func Supabase Functions for Gumloop integration using Edge Functions \##Explanation: Trigger and Function: The SQL code creates a trigger that calls the notify\_generate\_pdf\_change function whenever the generate\_pdf column is updated. If the new value is true, it sends a notification on the generate\_pdf\_channel with the proposal ID. Edge Function: The edge function listens for notifications on the generate\_pdf\_channel. When it receives a notification, it logs the proposal ID and can send data to Gumloop (you'll need to implement the actual integration logic). \[[https://pkjljvknmdozvzwnwprq.supabase.co/functions/v1/watch-generate-pdf](https://pkjljvknmdozvzwnwprq.supabase.co/functions/v1/watch-generate-pdf)] supabase functions download watch-generate-pdf *** ```Supabase Edge Function for generate_pdf boolean theme={null} import "jsr:@supabase/functions-js/edge-runtime.d.ts"; import { createClient } from "jsr:@supabase/supabase-js@2"; const supabaseUrl = Deno.env.get('SUPABASE_URL')!; const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY')!; const supabaseClient = createClient(supabaseUrl, supabaseAnonKey); const listenForGeneratePdfChanges = async () => { const { data, error } = await supabaseClient .from('generate_pdf_channel') .on('INSERT', payload => { const proposalId = payload.new.id; // Send data to Gumloop here console.log(`Gumloop flow triggered for proposal ID: ${proposalId}`); // Implement your Gumloop integration logic here }) .subscribe(); if (error) { console.error('Error subscribing to changes:', error); } }; Deno.serve(async (req: Request) => { await listenForGeneratePdfChanges(); return new Response('Listening for changes on generate_pdf...', { headers: { 'Content-Type': 'text/plain' }, }); }); ```