-
-
Save refringe/6545132 to your computer and use it in GitHub Desktop.
| 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; | |
| } | |
| } |
this will ensure that you are using a pretty URL
location / {
try_files $uri $uri/ $uri.html $uri.php$is_args$query_string;
}
and this will ensure that you are using a pretty URL with sendy settings.
location / {
try_files $uri $uri/ $uri.html $uri.php$is_args$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;
}
I tried a whole bunch of stuff. This is what finally worked for me (with certbot https). Sub-domain install of Sendy using nginx and SSL/TLS.
# Marketing (Sendy) Installation # server { root /var/www/marketing.site.com; index index.php index.html index.htm; server_name marketing.site.com; autoindex off; add_header X-Robots-Tag "noindex, noarchive"; 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/ /$uri.php$is_args$args; # $is_args converts to a ? if true } 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 ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|xml)$ { access_log off; log_not_found off; expires 30d; } # Added by certbot - remove these when copying this vhost to a new server block # listen [::]:443 ssl http2; # managed by Certbot listen 443 ssl http2; # managed by Certbot ssl_certificate /etc/letsencrypt/live/marketing.site.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/marketing.site.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = marketing.site.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; # listen [::]:80; server_name marketing.site.com; return 404; # managed by Certbot }
Thanks for this, it also worked for me but I found that I could not login. Using chatGPT I added the below after the other "add_header " and I could now login securely.
add_header Content-Security-Policy "upgrade-insecure-requests";
I tried a whole bunch of stuff. This is what finally worked for me (with certbot https). Sub-domain install of Sendy using nginx and SSL/TLS.
# Marketing (Sendy) Installation # server { root /var/www/marketing.site.com; index index.php index.html index.htm; server_name marketing.site.com; autoindex off; add_header X-Robots-Tag "noindex, noarchive"; 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/ /$uri.php$is_args$args; # $is_args converts to a ? if true } 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 ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|xml)$ { access_log off; log_not_found off; expires 30d; } # Added by certbot - remove these when copying this vhost to a new server block # listen [::]:443 ssl http2; # managed by Certbot listen 443 ssl http2; # managed by Certbot ssl_certificate /etc/letsencrypt/live/marketing.site.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/marketing.site.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = marketing.site.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; # listen [::]:80; server_name marketing.site.com; return 404; # managed by Certbot }
That helped. Thanks!
Thanks to everyone who contributed to this.
For anyone that is hosting in Azure App Service for Linux which uses nginx,
What I would advise is to first copy the original nginx file and then edit it based on the config above.
First:
cp /etc/nginx/sites-available/default /home/site/default
The above will copy the default file from the etc/nginx/sites-available to your deployment folder.
For example, this is what I got:
server {
#proxy_cache cache;
#proxy_cache_valid 200 1s;
listen 8080;
listen [::]:8080;
root /home/site/wwwroot;
index index.php index.html index.htm;
server_name example.com www.example.com;
port_in_redirect off;
location / {
index index.php index.html index.htm hostingstart.html;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /html/;
}
# Disable .git directory
location ~ /\.git {
deny all;
access_log off;
log_not_found off;
}
# Add locations of phpmyadmin here.
location ~* [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.[Pp][Hh][Pp])(|/.*)$;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_intercept_errors on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 3600;
fastcgi_read_timeout 3600;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
}
Then we can edit it based on the config shared above.
*Note, the main location / ... should include what you had from the original file. I went through pain because of this.
Also, the config for location ~* [^/]\.php(/|$) {.... should be kept
Final config is:
server {
#proxy_cache cache;
#proxy_cache_valid 200 1s;
listen 8080;
listen [::]:8080;
root /home/site/wwwroot;
index index.php index.html index.htm;
server_name www.example.com;
autoindex off;
port_in_redirect off;
location / {
index index.php index.html index.htm hostingstart.html; #make sure to include this
try_files $uri $uri/ $uri.html $uri.php$is_args$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;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /html/;
}
# Disable .git directory
location ~ /\.git {
deny all;
access_log off;
log_not_found off;
}
# Did not replace this
location ~* [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.[Pp][Hh][Pp])(|/.*)$;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param HTTP_PROXY "";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param QUERY_STRING $query_string;
fastcgi_index index.php;
fastcgi_intercept_errors on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 3600;
fastcgi_read_timeout 3600;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
}
location ~* ^.+\.(jpg|jpeg|gif|css|png|js|ico|xml)$ {
access_log off;
log_not_found off;
expires 30d;
}
}
Then run cp /home/site/default /etc/nginx/sites-available/default && service nginx restart via SSH
And also add cp /home/site/default /etc/nginx/sites-available/default && service nginx restart in the Startup Command under Configuration in your Azure Portal
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?
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.
🛠 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-fpm4️⃣ 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.
🛠 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;
}
Bascially all you really need is this
But to be on the safe side I added everything below:
And it works really well.