How can I merge these two configs together?

What I’m trying to do: Trying to merge two configs together

Where I’m stuck: It’s not working properly

What I’ve already tried: I tried using AI to solve it, but it doesn’t seem to be working

I am using CloudPanel to host my apps. This time, I’m trying to host the EspoCRM app, but it seems the vhost file isn’t working properly. I tried using AI chatbots to solve it, but I couldn’t figure it out.

CloudPanel default config:

server {
  listen 80;
  listen [::]:80;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  # Path to your SSL private key file
  {{ssl_certificate_key}}

  # Path to your SSL certificate file (public cert)
  {{ssl_certificate}}

  # Server names (domains) to respond to
  server_name www.example.com;

  # Redirect all requests to the non-www HTTPS domain
  return 301 https://example.com$request_uri;
}

server {
  listen 80;
  listen [::]:80;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  {{ssl_certificate_key}}    # SSL key path placeholder
  {{ssl_certificate}}        # SSL cert path placeholder

  server_name example.com www1.example.com;

  # Root directory of your website
  {{root}}

  # Access log file path
  {{nginx_access_log}}

  # Error log file path
  {{nginx_error_log}}

  # Redirect all HTTP requests to HTTPS
  if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
  }

  # Allow access to Let's Encrypt or other ACME challenge files
  location ~ /.well-known {
    auth_basic off;
    allow all;
  }

  # Additional custom settings you may want to include
  {{settings}}

  location / {
    # Proxy pass to backend or caching layer (e.g., Varnish)
    {{varnish_proxy_pass}}

    # Preserve original host headers and client IPs
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_hide_header X-Varnish;
    proxy_redirect off;

    # Proxy timeout and buffer settings
    proxy_max_temp_file_size 0;
    proxy_connect_timeout      720;
    proxy_send_timeout         720;
    proxy_read_timeout         720;
    proxy_buffer_size          128k;
    proxy_buffers              4 256k;
    proxy_busy_buffers_size    256k;
    proxy_temp_file_write_size 256k;
  }

  # Cache static assets and allow CORS from anywhere
  location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf|map|mjs)$ {
    add_header Access-Control-Allow-Origin "*";
    expires max;
    access_log off;
  }

  # Deny access to sensitive hidden files like .htaccess, .git, .svn
  location ~ /\.(ht|svn|git) {
    deny all;
  }

  # If the requested file exists, serve it directly
  if (-f $request_filename) {
    break;
  }
}

server {
  listen 8080;
  listen [::]:8080;

  server_name example.com www1.example.com;

  # Root directory of your website
  {{root}}

  # Try to serve the URI as a file, directory, or fallback to index.php
  try_files $uri $uri/ /index.php?$args;

  index index.php index.html;

  location ~ \.php$ {
    include fastcgi_params;

    # Handle FastCGI errors gracefully
    fastcgi_intercept_errors on;

    fastcgi_index index.php;

    # Path to the PHP script to execute
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

    # Return 404 if the file doesn't exist
    try_files $uri =404;

    # PHP-FPM timeout settings
    fastcgi_read_timeout 3600;
    fastcgi_send_timeout 3600;

    # Inform PHP that HTTPS is on and port is 443
    fastcgi_param HTTPS "on";
    fastcgi_param SERVER_PORT 443;

    # PHP-FPM backend address and port (replace with actual)
    fastcgi_pass 127.0.0.1:{{php_fpm_port}};

    # Additional PHP settings (memory limits, etc.)
    fastcgi_param PHP_VALUE "{{php_settings}}";
  }

  # If the requested file exists, serve it directly
  if (-f $request_filename) {
    break;
  }
}

Here’s the EspoCRM config:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name localhost; # domain name

    charset utf-8;
    index index.html index.php;

    client_max_body_size 50M;

    keepalive_timeout 300;
    types_hash_max_size 2048;

    server_tokens off;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;

    gzip on;
    gzip_types text/plain text/css text/javascript application/javascript application/json;
    gzip_min_length 1000;
    gzip_comp_level 9;

    root /path-to-espo/public; # path to public dir

    location /client {
        root /path-to-espo; # path to espocrm root dir
        autoindex off;

        location ~* ^.+\.(js|css|png|jpg|svg|svgz|jpeg|gif|ico|tpl)$ {
            access_log off;
            expires max;
        }
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    location ~ \.php$ {
        fastcgi_pass espocrm-php:9000;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param QUERY_STRING $query_string;
    }

    location /api/v1/ {
        if (!-e $request_filename){
            rewrite ^/api/v1/(.*)$ /api/v1/index.php last; break;
        }
    }

    location /portal/ {
        try_files $uri $uri/ /portal/index.php?$query_string;
    }

    location /api/v1/portal-access {
        if (!-e $request_filename){
            rewrite ^/api/v1/(.*)$ /api/v1/portal-access/index.php last; break;
        }
    }

    location ~ /(\.htaccess|\web.config|\.git) {
        deny all;
    }
}

More info:

I want to merge them together to make EspoCRM work with the CloudPanel default configuration. Please guide me on this. Thanks

1 Like

I am not sure what code editor you are working with but, how I would go about this is to drop them in VSCode, run a diff tool or use compare selected. Manually merge the two files using the info below as a guide for the config structure.

Take a whack at it using this method then if your still having issues include your attempt at a new config in a follow up post and we can have a look at it.

Other suggestions…

Keep in mind you don’t need to put everything in one config you can use the include directive to simplify how you sort out your blocks.

If you are using VSCode I recommend grabbing one of these extensions “NGINX Configuration Language Support” or “NGINX Configuration” these will vastly improve readability.

Configuration Structure

Include Directive

To test rapidly this site is very useful as well. It will help you iterate faster.

NGINX Playground

Good luck lets us know how it goes.

1 Like

Hey! Based on your setup, you’ll want to keep CloudPanel’s base config (with SSL, logging, redirection, etc.) and carefully merge the EspoCRM-specific location blocks into the main server block that handles requests (usually the one with the root and location /). Make sure /client, /api/v1/, /portal/ etc. are placed inside the right server block, and that the root is correctly pointed to /path-to-espo/public.

I actually faced a similar issue with a client’s Laravel app which they built for one of their site, which they built for real estate GP model on CloudPanel — the key was aligning the app’s root and ensuring PHP-FPM handling matched what the app expected. Once you get those paths and fastcgi_pass values right, it should click into place.

1 Like