Skip to content

Instantly share code, notes, and snippets.

@refringe
Last active August 11, 2025 14:38
Show Gist options
  • Select an option

  • Save refringe/6545132 to your computer and use it in GitHub Desktop.

Select an option

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;
}
}
@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','admin@example.com', MD5('StrongPassword123'));

-- Create default brand
INSERT INTO apps (app_name, from_name, from_email, reply_to, currency, app_key)
VALUES ('Default Brand','Admin','admin@example.com','admin@example.com','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