Skip to content

Instantly share code, notes, and snippets.

@refringe
Last active August 11, 2025 14:38
Show Gist options
  • Save refringe/6545132 to your computer and use it in GitHub Desktop.
Save refringe/6545132 to your computer and use it in GitHub Desktop.
Nginx configuration file example for Sendy (http://sendy.co/).
server {
listen 80;
listen [::]:80;
server_name domain.com;
autoindex off;
index index.php index.html;
root /srv/www/domain.com/public;
access_log /srv/www/domain.com/logs/access.log;
error_log /srv/www/domain.com/logs/error.log;
location / {
try_files $uri $uri/ $uri.php?$args;
}
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 ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
access_log off;
log_not_found off;
expires 30d;
}
}
@elfico
Copy link

elfico commented Feb 5, 2024

You do realise this is extremely bad practice as you are exposing your http configuration to the world by placing it in your www root directory?

Thanks for catching this!. Not sure how the files are served in nginx.

Moved it to a different folder.

@tiffneybare
Copy link

🛠 Fixing the Sendy /login Redirect Loop

If you get stuck in an infinite
/login?redirect=login?redirect=login...
loop in Sendy, here’s what worked for me:


1️⃣ Normalize the /login route in nginx

Add these rules inside your Sendy server block to strip extra redirect params and point directly to login.php:

location = /login {
    if ($arg_redirect) { return 301 /login; }  # strip any redirect param
    return 302 /login.php;
}
location = /login/ { return 301 /login; }

2️⃣ Seed the required DB tables

Sendy needs at least one user and one brand (apps entry) to operate.

USE sendy_db;

-- Create admin user
INSERT INTO login (name, email, password)
VALUES ('Admin','[email protected]', MD5('StrongPassword123'));

-- Create default brand
INSERT INTO apps (app_name, from_name, from_email, reply_to, currency, app_key)
VALUES ('Default Brand','Admin','[email protected]','[email protected]','USD','init-key');

3️⃣ Fix PHP session permissions

If PHP can’t write sessions, login state won’t persist.

php -i | grep "session.save_path"
# Usually /var/lib/php/sessions
sudo chown -R www-data:www-data /var/lib/php/sessions
sudo chmod 1733 /var/lib/php/sessions
sudo systemctl restart php8.3-fpm

4️⃣ Verify APP_PATH in config

In includes/config.php:

define('APP_PATH', 'https://sendy.redjuice.agency'); // exact domain, https, no trailing slash

✅ After these changes, the login loop stopped and I could access Sendy normally.

@tiffneybare
Copy link

🛠 Handling Pretty URLs in Sendy with nginx

If links like /logout or /settings download a .php file instead of loading the page, nginx is serving the file as static content instead of executing it with PHP-FPM.

Fix: Catch-all rewrite for extensionless URLs

This config snippet rewrites /route to /route.php if the file exists, otherwise falls back to index.php. It works for all routes, so you don’t need separate rules for /login, /logout, /settings, etc.

# Normal routing: serve files/dirs, else hand off to @extless
location / {
    try_files $uri $uri/ @extless;
}

# Handle extensionless routes
location @extless {
    if (-f $document_root$uri.php) {
        rewrite ^ /$uri.php last;    # internal rewrite → PHP-FPM
    }
    rewrite ^ /index.php?$args last; # fallback
}

# PHP handler
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock; # adjust PHP version if needed
}

# Sendy tracking rewrites (keep existing)
location ~ ^/(l|t|w|(un)?subscribe)/ {
    rewrite ^/([^/]+)/(.*)$ /$1.php?i=$2 last;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment