Configuring Sendy with NGINX: A Step-by-Step Guide
Tags: webdev, devops, php
Published: 2023-11-18 17:20:08

Sendy is a powerful and cost-effective self-hosted email marketing solution. To optimize its performance and security, integrating it with NGINX, a high-performance web server, is a smart choice. This article will guide you through the process of configuring Sendy with NGINX.

**<u>Prerequisites:</u>**
Before you begin, make sure you have the following:
Sendy project folder downloaded from SENDY on your server.
NGINX installed on your server.


## Step 1: Create NGINX Server Block for Sendy

Navigate to the NGINX sites-available directory. Create a new configuration file for Sendy, for example, sendy.conf.

`sudo nano /etc/nginx/sites-available/sendy.conf`

Add the following configuration, adjusting the values as needed:

For configure NGINX without SSL config

```
server {
    listen 80;
    server_name your_sendy_domain.com www.your_sendy_domain.com;

    root /var/www/sendy; # Change this to your Sendy installation directory

    index index.php index.html index.htm;
    autoindex off;

    add_header X-Robots-Tag "noindex, noarchive";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
    location ~ /\.  { deny all; log_not_found off; access_log off; return 404; }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust the PHP version if needed
        fastcgi_index index.php;
        fastcgi_param   SCRIPT_FILENAME $request_filename;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location ~* \.(css|js|gif|jpe?g|png)$ {
        expires max;
        log_not_found off;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location /l/ {
        rewrite ^/l/([a-zA-Z0-9/]+)$ /l.php?i=$1 last;
    }
    location /t/ {
        rewrite ^/t/([a-zA-Z0-9/]+)$ /t.php?i=$1 last;
    }
    location /w/ {
        rewrite ^/w/([a-zA-Z0-9/]+)$ /w.php?i=$1 last;
    }
    location /unsubscribe/ {
        rewrite ^/unsubscribe/(.*)$ /unsubscribe.php?i=$1 last;
    }
    location /subscribe/ {
        rewrite ^/subscribe/(.*)$ /subscribe.php?i=$1 last;
    }
    location /confirm/ {
        rewrite ^/confirm/(.*)$ /confirm.php?i=$1 last;
    }
    location /new-brand {
        rewrite ^/new-brand/?$ /new-brand.php last;
    }
    location /search-all-brands {
        rewrite ^/search-all-brands/?$ /search-all-brands.php last;
    }
    location /login {
        rewrite ^/login/?$ /login.php last;
    }
    location /settings {
        rewrite ^/settings/?$ /settings.php last;
    }
    location /two-factor {
        if ($arg_i) {
            rewrite ^/two-factor$ /two-factor.php last;
        }
    }
    location = /create {
        if ($arg_i) {
            rewrite ^/create$ /create.php last;
        }
    }
    location = /rules {
        if ($arg_i) {
            rewrite ^/rules$ /rules.php last;
        }
    }
    location = /edit {
       if ($arg_i) {
            rewrite ^/edit$ /edit.php last;
        }
    }
    location = /app {
         if ($arg_i) {
             rewrite ^/app$ /app.php last;
          }
    }
    location = /list {
         if ($arg_i) {
            rewrite ^/list$ /list.php last;
         }
    }
    location = /reports {
        if ($arg_i) {
             rewrite ^/reports$ /reports.php last;
        }
    }
    location = /edit-brand {
        if ($arg_i) {
            rewrite ^/edit-brand$ /edit-brand.php last;
         }
    }
    location = /templates {
        if ($arg_i) {
           rewrite ^/templates$ /templates.php last;
        }
    }
    location = /report {
        if ($arg_i) {
            rewrite ^/report$ /report.php last;
        }
    }
    location = /send-to {
        if ($arg_i) {
            rewrite ^/send-to$ /send-to.php last;
        }
    }
    location = /autoresponders-emails {
        if ($arg_i) {
            rewrite ^/autoresponders-emails$ /autoresponders-emails.php last;
        }
    }
    location = /autoresponders-list {
        if ($arg_i) {
            rewrite ^/autoresponders-list$ /autoresponders-list.php last;
        }
    }
    location = /autoresponders-edit {
        if ($arg_i) {
            rewrite ^/autoresponders-edit$ /autoresponders-edit.php last;
        }
    }
    location = /segments-list {
        if ($arg_i) {
           rewrite ^/segments-list$ /segments-list.php last;
        }
    }
    location = /segment {
        if ($arg_i) {
           rewrite ^/segment$ /segment.php last;
        }
    }
    location = /create-template {
        if ($arg_i) {
           rewrite ^/create-template$ /create-template.php last;
        }
    }
    location = /edit-template{
        if ($arg_i) {
           rewrite ^/edit-template$ /edit-template.php last;
        }
    }
    location = /template-preview {
        if ($arg_i) {
            rewrite ^/template-preview$ /template-preview.php last;
        }
    }
    location = /new-list {
        if ($arg_i) {
            rewrite ^/new-list$ /new-list.php last;
        }
    }
    location = /subscribers {
         if ($arg_i) {
            rewrite ^/subscribers$ /subscribers.php last;
         }
    }
    location = /custom-fields {
         if ($arg_i) {
            rewrite ^/custom-fields$ /custom-fields.php last;
         }
    }
    location = /remove-duplicates {
         if ($arg_i) {
            rewrite ^/remove-duplicates$ /remove-duplicates.php last;
         }
    }
    location = /blacklist-blocked-domains {
         if ($arg_i) {
            rewrite ^/blacklist-blocked-domains$ /blacklist-blocked-domains.php last;
         }
    }
    location = /delete-from-list {
         if ($arg_i) {
            rewrite ^/delete-from-list$ /delete-from-list.php last;
         }
    }
    location = /blacklist-suppression {
         if ($arg_i) {
            rewrite ^/blacklist-suppression$ /blacklist-suppression.php last;
         }
    }
    location = /unsubscribe-from-list {
         if ($arg_i) {
            rewrite ^/unsubscribe-from-list$ /unsubscribe-from-list.php last;
         }
    }
    location = /update-list {
         if ($arg_i) {
            rewrite ^/update-list$ /update-list.php last;
         }
    }
    location ~ ^/housekeeping-(\w+)$ {
         rewrite ^/housekeeping-(\w+)$ /housekeeping-$1.php last;
    }

    access_log /var/log/nginx/sendy_access.log;
    error_log /var/log/nginx/sendy_error.log;
}
```

For configure NGINX with SSL config

```server {
    server_name your_sendy_domain.com www.your_sendy_domain.com;
    root /var/www/sendy; # Change this to your Sendy installation directory

    index index.php index.html index.htm;
    autoindex off;

    add_header X-Robots-Tag "noindex, noarchive";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
    location ~ /\.  { deny all; log_not_found off; access_log off; return 404; }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust the PHP version if needed
        fastcgi_index index.php;
        fastcgi_param   SCRIPT_FILENAME $request_filename;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location ~* \.(css|js|gif|jpe?g|png)$ {
        expires max;
        log_not_found off;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location /l/ {
        rewrite ^/l/([a-zA-Z0-9/]+)$ /l.php?i=$1 last;
    }
    location /t/ {
        rewrite ^/t/([a-zA-Z0-9/]+)$ /t.php?i=$1 last;
    }
    location /w/ {
        rewrite ^/w/([a-zA-Z0-9/]+)$ /w.php?i=$1 last;
    }
    location /unsubscribe/ {
        rewrite ^/unsubscribe/(.*)$ /unsubscribe.php?i=$1 last;
    }
    location /subscribe/ {
        rewrite ^/subscribe/(.*)$ /subscribe.php?i=$1 last;
    }
    location /confirm/ {
        rewrite ^/confirm/(.*)$ /confirm.php?i=$1 last;
    }
    location /new-brand {
        rewrite ^/new-brand/?$ /new-brand.php last;
    }
    location /search-all-brands {
        rewrite ^/search-all-brands/?$ /search-all-brands.php last;
    }
    location /login {
        rewrite ^/login/?$ /login.php last;
    }
    location /settings {
        rewrite ^/settings/?$ /settings.php last;
    }
    location /two-factor {
        if ($arg_i) {
            rewrite ^/two-factor$ /two-factor.php last;
        }
    }
    location = /create {
        if ($arg_i) {
            rewrite ^/create$ /create.php last;
        }
    }
    location = /rules {
        if ($arg_i) {
            rewrite ^/rules$ /rules.php last;
        }
    }
    location = /edit {
       if ($arg_i) {
            rewrite ^/edit$ /edit.php last;
        }
    }
    location = /app {
         if ($arg_i) {
             rewrite ^/app$ /app.php last;
          }
    }
    location = /list {
         if ($arg_i) {
            rewrite ^/list$ /list.php last;
         }
    }
    location = /reports {
        if ($arg_i) {
             rewrite ^/reports$ /reports.php last;
        }
    }
    location = /edit-brand {
        if ($arg_i) {
            rewrite ^/edit-brand$ /edit-brand.php last;
         }
    }
    location = /templates {
        if ($arg_i) {
           rewrite ^/templates$ /templates.php last;
        }
    }
    location = /report {
        if ($arg_i) {
            rewrite ^/report$ /report.php last;
        }
    }
    location = /send-to {
        if ($arg_i) {
            rewrite ^/send-to$ /send-to.php last;
        }
    }
    location = /autoresponders-emails {
        if ($arg_i) {
            rewrite ^/autoresponders-emails$ /autoresponders-emails.php last;
        }
    }
    location = /autoresponders-list {
        if ($arg_i) {
            rewrite ^/autoresponders-list$ /autoresponders-list.php last;
        }
    }
    location = /autoresponders-edit {
        if ($arg_i) {
            rewrite ^/autoresponders-edit$ /autoresponders-edit.php last;
        }
    }
    location = /segments-list {
        if ($arg_i) {
           rewrite ^/segments-list$ /segments-list.php last;
        }
    }
    location = /segment {
        if ($arg_i) {
           rewrite ^/segment$ /segment.php last;
        }
    }
    location = /create-template {
        if ($arg_i) {
           rewrite ^/create-template$ /create-template.php last;
        }
    }
    location = /edit-template{
        if ($arg_i) {
           rewrite ^/edit-template$ /edit-template.php last;
        }
    }
    location = /template-preview {
        if ($arg_i) {
            rewrite ^/template-preview$ /template-preview.php last;
        }
    }
    location = /new-list {
        if ($arg_i) {
            rewrite ^/new-list$ /new-list.php last;
        }
    }
    location = /subscribers {
         if ($arg_i) {
            rewrite ^/subscribers$ /subscribers.php last;
         }
    }
    location = /custom-fields {
         if ($arg_i) {
            rewrite ^/custom-fields$ /custom-fields.php last;
         }
    }
    location = /remove-duplicates {
         if ($arg_i) {
            rewrite ^/remove-duplicates$ /remove-duplicates.php last;
         }
    }
    location = /blacklist-blocked-domains {
         if ($arg_i) {
            rewrite ^/blacklist-blocked-domains$ /blacklist-blocked-domains.php last;
         }
    }
    location = /delete-from-list {
         if ($arg_i) {
            rewrite ^/delete-from-list$ /delete-from-list.php last;
         }
    }
    location = /blacklist-suppression {
         if ($arg_i) {
            rewrite ^/blacklist-suppression$ /blacklist-suppression.php last;
         }
    }
    location = /unsubscribe-from-list {
         if ($arg_i) {
            rewrite ^/unsubscribe-from-list$ /unsubscribe-from-list.php last;
         }
    }
    location = /update-list {
         if ($arg_i) {
            rewrite ^/update-list$ /update-list.php last;
         }
    }
    location ~ ^/housekeeping-(\w+)$ {
         rewrite ^/housekeeping-(\w+)$ /housekeeping-$1.php last;
    }

    access_log /var/log/nginx/sendy_access.log;
    error_log /var/log/nginx/sendy_error.log;

    listen 443 ssl http2;
    ssl_certificate /path/to/your/ssl_certificate.crt;
    ssl_certificate_key /path/to/your/ssl_certificate_key.key;
}

server {
    if ($host = your_sendy_domain.com) {
        return 301 https://$host$request_uri;
    }
    listen 80;
    server_name your_sendy_domain.com;
    return 404;
}```

Save the file and create a symbolic link to it in the sites-enabled directory:

`sudo ln -s /etc/nginx/sites-available/sendy.conf /etc/nginx/sites-enabled/`

Test the NGINX configuration:

`sudo nginx -t`

If the test is successful, reload NGINX:

sudo service nginx reload

## Step 2: Update Sendy Configuration

Edit the Sendy settings file:

`nano /var/www/sendy/includes/config.php`

Update the following lines with your server information:

```define('APP_PATH', 'https://your_sendy_installation_url');

/*  MySQL database connection credentials (place values between the apostrophes) */
$dbHost = ''; //MySQL Hostname
$dbUser = ''; //MySQL Username
$dbPass = ''; //MySQL Password
$dbName = ''; //MySQL Database Name

/*  Set this if you use a non standard MySQL port.  */
$dbPort = 3306; ```

Save the changes and exit.

## Step 3: Test the Configuration

Open your web browser and navigate to your Sendy domain. If everything is configured correctly, you should see the Sendy login page.