Yourls: Add Official Support for Nginx

Created on 13 Jun 2014  ·  71Comments  ·  Source: YOURLS/YOURLS

Nginx is becoming a very widely used httpd lately. YOURLS should have some official support for the httpd so it can be used on more platforms. All you need to do is make a config for us Nginx users in the wiki :P

docs enhancement server

Most helpful comment

@ozh, the baseline stuff you need out of the config is

  if ( $uri !~ ^/(admin) ){
    set $rule_0 1$rule_0;
  }
  if (!-f $request_filename){
    set $rule_0 2$rule_0;
  }
  if (!-d $request_filename){
    set $rule_0 3$rule_0;
  }
  if ($rule_0 = "321"){
    rewrite ^/.*$ /yourls-loader.php last;
  }

and add this if you want the redirect to non-www

  if ($http_host ~* "^www.(.*)$"){
    set $rulea_0 1$rulea_0;
    set $bref_1 $1;
  }
  if ($rulea_0 = "1"){
    rewrite ^/(.*)$ http://$bref_1/$1 permanent;
  }

It's very true that Nginx has many configs, but if a lot of the configs to the same thing. If you want, I can test this as widely as I can and I'll get back to you :) Just let me know.

All 71 comments

Yes, this is already in our minds.

Related: #1652

@LeoColomb, Yeah, I saw that one when I searched for Nginx but it didn't seem to come to a conclusion. Can't wait for 2.0 :D

@LeoColomb, I have managed to get a working Nginx config working for YOURLS. A censored copy is below :)

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

  root /srv/http/website/public;
  index index.php index.html index.htm;

  server_name website;

  # Logging
  access_log /srv/http/website/log/access.log;
  error_log /srv/http/website/log/error.log warn;

  # Custom Stuff
  if ( $uri !~ ^/(robots\.txt|favicon\.ico|admin) ){
    set $rule_0 1$rule_0;
  }
  if (!-f $request_filename){
    set $rule_0 2$rule_0;
  }
  if (!-d $request_filename){
    set $rule_0 3$rule_0;
  }
  if ($rule_0 = "321"){
    rewrite ^/.*$ /yourls-loader.php last;
  }

  location ~ config.php {
    deny all;
  }

  # Error pages?
  location / {
    try_files $uri $uri/ =404;
  }

  # Remove WWW
  if ($http_host ~* "^www.(.*)$"){
    set $rulea_0 1$rulea_0;
    set $bref_1 $1;
  }
  if ($rulea_0 = "1"){
    rewrite ^/(.*)$ http://$bref_1/$1 permanent;
  }

  # Static File Caching?
  location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1d;
  }

  # Pass PHP files to FPM.
  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;
  }

  # Deny hidden files.
  location ~ /\. {
    deny all;
  }
}

There are several custom stuff here (handling robots.txt, favicon, caching static files) and this seems also tied to PHP-FPM on Linux)

The problem with nginx is that it seems there are as many configs as there are servers (yours, this one, this one, that one, and more)

Based on what I read I'm not sure we can provide a generic works-for-all nginx config, maybe at best it would be pointers in a wiki

Anyway I don't think 2.0 is a relevant milestone. This should be either fixed ASAP if doable, or wontfixed

@ozh, the baseline stuff you need out of the config is

  if ( $uri !~ ^/(admin) ){
    set $rule_0 1$rule_0;
  }
  if (!-f $request_filename){
    set $rule_0 2$rule_0;
  }
  if (!-d $request_filename){
    set $rule_0 3$rule_0;
  }
  if ($rule_0 = "321"){
    rewrite ^/.*$ /yourls-loader.php last;
  }

and add this if you want the redirect to non-www

  if ($http_host ~* "^www.(.*)$"){
    set $rulea_0 1$rulea_0;
    set $bref_1 $1;
  }
  if ($rulea_0 = "1"){
    rewrite ^/(.*)$ http://$bref_1/$1 permanent;
  }

It's very true that Nginx has many configs, but if a lot of the configs to the same thing. If you want, I can test this as widely as I can and I'll get back to you :) Just let me know.

Sure, all feedback is very welcome. Ideally, the nginx config (as all other things) should be tested under all the OS (Win / MacOS / various Linux flavors including FreeBSD which always seems to behave slightly differently regarding several stuff), with YOURLS installed at domain root or in a subfolder, using various flavors of PHP (as cgi, with suexec, etc...) and any other possible combination one could think of :)

Alrighty, let me pull the rest of my stuff online and I will get cracking :P

@ozh, I have tested with success for Nginx + PHP-FPM on Ubuntu 14.04, Ubuntu 13.10, Arch 2014.06.01, and Debian 7.5. I currently do not have a place that supports a FreeBSD and CentOS install.

@ZacharyDuBois Thanks for the updates.

Just wanted to add to this thread that I'm running YOURLS on a FreeBSD 10.0 machine with nginx/1.6.0 and php-fpm 5.5.11 running in separate FreeBSD jails for security. I'm happy to share my configuration if this is helpful.

@ZacharyDuBois : The if directive within nginx.conf should be avoided: See http://wiki.nginx.org/IfIsEvil and http://wiki.nginx.org/Pitfalls#Using_If

Redirecting to non-www without using if is as simple as:

server {
    listen        80;                 # IPv4
    listen        [::]:80;            # IPv6
    listen        443 ssl;            # IPv4 SSL
    listen        [::]:443 ssl;       # IPv6 SSL
    ssl_certificate       ssl/server.crt;
    ssl_certificate_key   ssl/server.key;
    server_name   www.chtaube.eu;
    return        301  $scheme://chtaube.eu$request_uri;
}

This handles IPv4, IPv6, http and https.

@chtaube, I understand the risks of IF statements inside of an Nginx config. The only danger exists is when they are inside a location block. As said here "Directive if has problems when used in location context". I have not had an issue when using them in the server blocks.

Also, you should separate SSL and non-SSL into to different servers.

There is no real problem because with Nginx, there are infinite ways to do the something. Some are more efficient than others and some are faster. Right now, my YOURLs does not get enough traffic to worry about the efficiency or speed.

Please do share you config if yours is working :) It would be a great help for the rest of us.

Here's what I have working on my site, Debian 7, nginx 1.6 and PHP-FPM 5.4.30 (dotdeb)

server {

        listen 80;
        listen [::]:80;
        listen 443 ssl;
        listen [::]:443 ssl;

        ssl_certificate    /path/to/cert/exm.pl.crt;
        ssl_certificate_key    /path/to/cert/exm.pl.key;


        server_name exm.pl www.exm.pl;
        access_log /srv/logs/access/exm.pl.log;
        error_log /srv/logs/error/exm.pl.log;
        root /srv/www/exm.pl/public_html;

        location / {
                try_files $uri $uri/ /yourls-loader.php;
                index index.php;
                location ~ \.php$ {

                        include /etc/nginx/fastcgi_params;
                        fastcgi_pass    unix:/var/run/php5-fpm.sock;
                        fastcgi_index index.php;
                        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                }
        }
}

Edit: Added missing listen 443 ssl listen directive.

Been running YOURLs 1.7 with NGINX stable on Ubuntu 14.04 without issue. FWIW here's my configs

Primary vhost:

server {
        listen     80;

        include siteconf/shortsite.common.conf;

        rewrite ^/admin/(.*) https://$server_name/admin/$1 permanent;
        rewrite ^/$ http://mainsite.com permanent;

}

server {
        listen     443 ssl spdy default_server;

        ssl on;
        ssl_certificate /etc/nginx/ssl/somecert.crt;
        ssl_certificate_key /etc/nginx/ssl/somekey.key;

        ssl_session_timeout 5m;

        ssl_protocols             TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers               ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
        ssl_buffer_size           8k;

        ssl_session_cache   shared:SSL:10m;

        include siteconf/shortsite.common.conf;

        rewrite ^/$ http://mainsite.com permanent;

}

And the shared conf:

server_name  shorturl;

access_log  /var/log/nginx/shorturl.access.log  main;
error_log  /var/log/nginx/shorturl.error.log warn;

root   /home/siteuser/htdocs;
index  index.php;

set $memcached_key $uri;

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

location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
}

location / {
        try_files $uri $uri/ /yourls-loader.php?$args;
}

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires 24h;
        log_not_found off;
}

location ~ \.php$ {
        try_files $uri /yourls-loader.php;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass   unix:/var/run/siteuser.sock;
}

@fergbrain, why do you have SSL set on a non-SSL port? Also, why is the PHP block and index block inside of a location block? That breaks every rule of Nginx. See this.

@ChrisWiegman, I have been running YOURLs well with my config too but others seem to have different outcomes. Also, from experience, it is best to move that file caching block below the PHP one. Sometimes PHP can serve special files and then the cache block doesn't get them.

Again, I have tested my config with Nginx + PHP-FPM on Ubuntu 14.04 LTS, Ubuntu 13.10, Arch 2014.06.01, and Debian 7.5.

I've put my configuration here: http://chtau.be/nginxconfig


@ZacharyDuBois for the SSL stuff: the configuration

    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;

enables a non-SSL server on port 80 and a SSL-enabled server on port 443, both configured within a single server-configuration block. The upcoming ssl_*-directives configure only the SSL part of the server.

http://nginx.org/en/docs/http/configuring_https_servers.html#single_http_https_server

@chtaube, Ah sweet. I did not know this. I have always been making a blank port 80 server block with just a rewrite over to the SSL block. I will add this in my server configs. Thanks! :)

Please note there's some really bad info in this thread. Using "if" is really bad, and you DO NOT create a "blank" server just to make rewrites!

@ChrisWiegman has it right.

I've been very happily using the following config for over 2 years with yourls and nginx:
http://packetcollision.com/2012/01/27/yourls-and-nginx-an-updated-config/

It's as simple as this (this is the example config given)

server {
  listen 178.33.177.161:80;
  server_name pcurl.us;
  root /var/www/pcurl.us/htdocs;
  location / {
    try_files $uri $uri/ /yourls-loader.php;
    location ~ \.php$ {
      fastcgi_pass   unix:/var/run/php5-fpm.sock;;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      include        fastcgi_params;
    }
  }
}

OK, thanks everyone, apparently the easier and cleaner solution seems look like this:

server {

  # Listen IPv4 & v6
  listen 80;
  listen [::]:80;

  # Optional SSL stuff
  listen              443              ssl;
  listen              [::]:443         ssl;
  ssl_certificate     example.com.crt;
  ssl_certificate_key example.com.key;

  # Server names
  server_name example.com www.example.com;

  # Root directory (NEED CONFIGURATION)
  root /path/to/files;

  # Rewrites
  location / {

    # Try files, then folders, then yourls-loader.php
    # --- The most important line ---
    try_files $uri $uri/ /yourls-loader.php;

    # PHP engine
    location ~ \.php$ {
      fastcgi_pass   unix:/var/run/php5-fpm.sock; # Can be different
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      include        fastcgi_params;
    }
  }
}

Do you agree?

@LeoColomb - yes, that's a :+1: from me :)

@LeoColomb Same here!

Hmm, this is odd - new install, same config, only difference I can find is that nginx is version 1.7.4. All other aspects of YOURLS work fine, but the actual redirect just says "404 not found" for me. There's a guy over at StackOverflow seems to be having similar problems - http://stackoverflow.com/questions/25082696/yourls-redirection-not-working-in-nginx-file-downloads-instead

Driving me crazy - spent 7 hours at it today, been through debug logs and everything. Weird.

Did you include the MIME types somewhere into nginx.conf? There should be a file called mime.types (it seems to be shipped with nginx).

In my configuration, it is included right in the http { … } section. This way it should apply to every server { … } configuration block.

http {
    include mime.types;
    default_type   application/octet-stream;

    … (more configuration stuff) …

    server {
        …
    }

    server {
        …
    }
}

Another thing: When opening user/config.php or any other PHP-file into an editor, please be careful that you save the file as plain ASCII.

Some unicode-aware editors seem to add a byte order mark (BOM) to the top of the file. PHP just echoes this BOM to the browser, preventing the sending of header information (like redirects, cookies, …).

If you use Firefox you can use the Firebug extension to take a detailed look at the server response.

yourls-garbage_anon

Both very good points, and should be part of the wiki. But don't seem to apply to me. It's still either 404 or the actual yourls_load code.

In fact, this morning I've started using my own redirector: move the YOURLS app to a different location and use the API to pull the location, then set the location as a php header. A bit of a crappy workaround, but gets me going while I figure out nginx...

@digitaltoast Did you have your server { … } configuration from nginx.conf posted anywhere here? Maybe I see something you might have missed.

Thanks @chtaube - OK, I just spun up a brand new, fresh LEMP droplet (ubuntu 14.04, php5.5, nginx stable 1.4.6) and installed a brand new YOURLS in a subdirectory called "yourls".

Only added one little bit to the nginx config, the lines

        location /yourls/ {
                try_files $uri $uri/ /yourls/yourls-loader.php =404;
        }

which now looks like this: https://gist.github.com/digitaltoast/7b5a3c259216225f09f3

And it's doing the same thing as the other guy was getting - everything else works fine, I can add and amend short URLS, the API works fine, but when using the redirects, the server attempts to download the yourls-loader file. Do you want me to turn debug and redirect logging on and post the output as a gist somewhere?

(EDIT: I do like the fact that github has proper nginx config file markdown parsing!)

You have two location blocks starting with

location ~ \.php$ {
    …

nginx only uses the first location block that matches. The second one would be never used.


In the first location block, try adding

    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

somewhere in location ~ \.php$ { … }

I have this line in my configuration file and it seems to be mandatory.

Ugh! Well spotted! It must be a late night last night - OK, have modified my config and updated my gist(https://gist.github.com/digitaltoast/7b5a3c259216225f09f3) however it is still serving it as a file.

The only thing I see different is that mine is in a subdirectory and yours is at the root level.

Maybe just an idea… but please take a look at the nginx manual about how location-blocks are handled in nginx.conf.

nginx reads location blocks in a specific order and only the configuration given in the first match is applied. You will likely have a location block like location ~ \.php { … } for defining your php-fpm/-cgi gateway. If you add another location-block which matches the URI request, it is possible that the php-fpm/-cgi gateway configuration is never applied and in result *.php files are not handled by the php gateway.


A location can either be defined by a prefix string, or by a regular expression. Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching). To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

@digitaltoast Can you (temporarily) rewrite it this way:

server {
    listen 80 default_server;

    root /usr/share/nginx/html;
    index index.php index.html index.htm;

    server_name localhost;
    try_files $uri $uri/ /yourls/yourls-loader.php =404;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

Thanks @chtaube - but I'm still getting the redirect served as a download of the yours-loader file.

Weird, eh? Time for a rewrite log? I don't expect you to be debugging my issues, but if you're interested or intrigued, contact me privately and I can give you a login so you can have a play around as it's only a temporary instance of a server you can't do much harm!

@digitaltoast I was able to reproduce your issue on my test server and I think I found something:

Within the server { … } config block, remove that =404 from the try_files statement. It must look like this:

try_files $uri $uri/ /yourls/yourls-loader.php;

But keep the =404 within the location ~ \.php$ { … } block untouched – This one is important!

@chtaube YES YES YES! :+1: Spot on! So it looks like the only difference is

try_files $uri =404;

in the php section? I wonder what is different about the php/nginx/whatever between my old and new server? Anyway, problem fixed.

So THIS below is definitely a working config for me, anyway - you can make a stackoverflow answer and get some points - I'll rate you up!

Thanks again SO much.

server {
    listen 80 default_server;

    root /usr/share/nginx/html;
    index index.php index.html index.htm;

    server_name localhost;
    try_files $uri $uri/ /yourls/yourls-loader.php;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

Is that considered a fix for a peculiar situation, or should I update the previously recommended config ?

@ozh The error was in that =404 he added here:

    try_files $uri $uri/ /yourls/yourls-loader.php =404;   # wrong!

Anyway, try_files $uri =404; in the php location block is still a recommended security improvement. It checks that the file actually exists before handing over to the php-fpm gateway. This was exploited some time ago to feed user uploaded files to the PHP engine. Recent PHP versions seem to check the file extension, too. But an extra check doesn't hurt, IMO.

So, my suggestion would be to add it like this to the recommended config:

    location ~ \.php$ {
        try_files $uri =404;
        …

Hi Everyone,
I hope you guys could help me possibly get this working I set up YOURLS on my server running debian 6 php 5.3.29 nginx 1.6.2. I have followed the recommendations on the list here, trying multiple versions of the working configs and made the necessary changes but it still seems that there is something I am missing. I am receiving the infernal 403 Forbidden, I checked my folder and file permissions and they are correct afaik nothing out of the ordinary. When I turn autoindex on I can see the folder contents starting with docroot but say when I click to load yourls-loader.php all I get is redirected to the docroot.
Here is my config not sure if it is an obvious error and I am just not seeing it or if it is something else and just don't know where to look.

server {

  # Listen IPv4 & v6
  listen 80;
  listen [::]:80;

  # Optional SSL stuff
  #listen              443              ssl;
  #listen              [::]:443         ssl;
  #ssl_certificate     example.com.crt;
  #ssl_certificate_key example.com.key;

  # Server names
  server_name <url>;

  # Root directory (NEEDS CONFIGURATION)
  root /var/www/<url>;
  index index.php index.html index.htm;

  # Logging
  access_log /var/log/nginx/<url>.access.log;
  error_log /var/log/nginx/<url>.error.log warn;

  # Static File Caching?
  location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1d;
  }

  # Rewrites
  location / {

    # Try files, then folders, then yourls-loader.php
    # --- The most important line ---
    try_files $uri $uri/ /yourls-loader.php;
    #autoindex on;



    # PHP engine
    location ~ \.php$ {
      try_files      $uri =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass   unix:/var/run/php5-fpm/<url>.socket; # Can be different
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      include        /etc/nginx/fastcgi_params;
    }
  }
}

My error log output looks like this

[error] 6624#0: *1227 directory index of "/var/www/<url>/" is forbidden, client: <ip>, server: <url>, request: "GET / HTTP/1.1", host: "<url>"

Thank you, and I apologize if this is a stupid easy question to figure out.

edit: I had initially separated out, the php location statement from the general location statement, lo and behold that if you do this your shorteened urls will not work you will receive a 404 error, I fixed it as it is originally on the suggested working template and it works properly, I just did not want to have this snipet here and have someone potentially try and use it as a template with a glaring issue in it.

Are you trying to get to the admin? If so, try just appending /admin/ to your yourls site URL.
If not, try /admin/index.php

Also, if your YOURLS is at the root level (ie: your short urls are not mysite.com/123 and not mysite.com/short/123 ) then try commenting out

location / {
    try_files $uri $uri/ /yourls-loader.php;

I can get to the admin if I type my.url/admin or my.url/admin/index.php both work and I get to the admin interface. But if I just type my.url I get the 403 error if I also try my.url/yourls-loader.php i also get 403, I'll try comenting out the try_files directive, though I think I already tried doing that with no success.

I had a similar issue that I solved by removing a slash in my YOURLS config
file (not the nginx config).

Maybe that spurs something for you?

On Thu, Dec 18, 2014 at 4:41 PM, Mark Sanger [email protected]
wrote:

I can get to the admin if I type my.url/admin or my.url/admin/index.php
both work and I get to the admin interface. But if I just type my.url I get
the 403 error if I also try my.url/yourls-loader.php i also get 403, I'll
try comenting out the try_files directive, though I think I already tried
doing that with no success.


Reply to this email directly or view it on GitHub
https://github.com/YOURLS/YOURLS/issues/1715#issuecomment-67570063.

But... you're not supposed to access yourls-loader directly, are you?
In other words, either you're going to the admin to admin it, or you're visiting a short url.
Or am I missing something? Also, try removing that slash as @LunkRat mentioned :)

:+1: @digitaltoast this is my first foray with yourls but from the examples I have seen the docroot should display a public interface where anyone can create their own shortened url without any restriction. only the admin is restricted if you set define( 'YOURLS_PRIVATE', true );

@LunkRat do you mean the user/config.php I had considered this and revisted the file the only location that might have an errant trailing slash is define( 'YOURLS_SITE', 'http://my.url' ); but I did not have one there and adding it did not change the behavior

@msanger the default is to have 403 at the docroot.

@digitaltoast can fill you in better than I can about implementing a public interface.

ohhh :facepalm: I see then I had a completely wrong view on what the default behavior is supposed to be. thank you for opening my eyes!

thank you for the excellent help, I have found https://github.com/YOURLS/YOURLS/wiki/Private-Or-Public I think I'll be able to go from there and get what I want running.

Took a few hours to find the right NGINX vhost configuration and to get acquainted with YOURLS, but she's running just fine on NGINX 1.7.9 over HTTPS, Debian Linux. Felt real good when it light up finally. Thanks, developers.

I'm not sure if this helps this conversation. But I was pulling my hair out about this. I diligently went through all of your potential fixes with no luck. Because I am cheap I am running yourls on the same machine as wordpress multisite.

I'm really not sure what the interaction was but when I renamed the admin folder from 'admin' to 'booger' and then the url references in the php files, it all started to work. There was something about the word 'admin' that (I believe) wpmu was screwing with.

Here is my newer config. I should've updated this here awhile ago.

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

  server_name domain.tld;

  return 301 https://domain.tld$request_uri;
}
server {
  listen 443 ssl spdy;
  listen [::]:443 ssl spdy;

  root /srv/http/site/public;
  index index.php index.html index.htm;

  server_name domain.tld;

  add_header Strict-Transport-Security "max-age=31536000; preload";
  add_header Alternate-Protocol 443:npn-spdy/3,443:npn-spdy/2;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  spdy_headers_comp 6;
  ssl on;
  ssl_certificate /etc/nginx/ssl/ssl.crt;
  ssl_certificate_key /etc/nginx/ssl/ssl.key;
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_trusted_certificate /etc/nginx/ssl/trustchain.crt;

  location ~ /\. {
    deny all;
  }

  location /user {
    # Note: Remove this if you have plugins that load images or JS (Like random background images).
    deny all;
  }

  location / {
    try_files $uri $uri/ /yourls-loader.php;
  }

  # Pass PHP files to FPM.
  location ~* \.php(?:$|/) {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    fastcgi_buffers 8 16k;
    fastcgi_buffer_size 32k;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param HTTPS on;
  }

  location ~*.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
  }
}

Hello ,

in order to make yourls work with plugin "Redirect with GET paramaeters" on nGinx you need to keep the query args :

try_files $uri $uri/ /yourls-loader.php?$query_string;

Hi guys, I need help

I am using this nginx config but I kept getting 403

server {

  # Listen IPv4 & v6
  listen 80;
  listen [::]:80;

  # Server names
  server_name example.xyz;

  # Root directory (NEEDS CONFIGURATION)
  root /home/yourls;
  index index.php index.html

  # Rewrites
  location / {

    # Try files, then folders, then yourls-loader.php
    # --- The most important line ---
    try_files $uri $uri/ /yourls-loader.php;

    # PHP engine
    location ~ \.php$ {
      try_files      $uri =404;
      fastcgi_pass   unix:/var/run/php7-fpm.sock; # Can be different
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
      include        fastcgi_params;
    }
  }
}

I fixed my error 403 with this config

server {
    listen      80;
    server_name example.xyz;
    root        /home/yourls;

    access_log /home/yourls/logs/access.log;
    error_log /home/yourls/logs/error.log;

    index index.php;

    location / {
        try_files $uri $uri/ /yourls-loader.php;
        expires 14d;
        add_header Cache-Control 'public';
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
    }
}

Hello. I follow this instruction https://github.com/YOURLS/YOURLS/wiki/Nginx-configuration

But it's instead downloading the yourls.php than opening my generated link.

What's wrong with my config?
`server {
listen 80;
listen [::]:80;

listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;

root $MYDOCROOT;

index index.php index.html index.htm index.nginx-debian.html;

server_name $SERVERNAME;

include snippets/$SSLCONF.conf;
include snippets/SSLPARAMS.conf;

location / {
    try_files $uri $uri/ /yourls-loader.php =404;
}   

location ~ \.php$ {
    include     snippets/fastcgi-php.conf;
    fastcgi_pass    unix:/run/php/php7.0-fpm.sock;
    fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include     fastcgi_params;

}

location ~ /\.ht {
    deny all;
}

location ~ /.well-known {
    allow all;
}

}`
Btw, what's default permission for all files and folder in YOURLS?

I used 755 for folder and 640 for files.

@cloudymous
yours fastcgi_pass unix:/run/php/php7.0-fpm.sock;
should be fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;

@skeith I have change that and still download .php files when i try to visit generated link.

I also follow your configuration up there but still download the .php file.

Hi all,
I'm using the config from the wiki, with the exception of try_files $uri $uri/ /yourls-loader.php index.php?$args /index.php?$args;
However, when I go to mysite/ it tries to download it as a file. I tried /pages/page.php, but that said I was accessing an unallowed area and I was redirected back to the homepage.
Any thoughts?
-Michael.

With more digging, it's turned out it's downloading the yourls-loader.php. So somehow try_files isn't telling nginx it's a php file. Very odd.

For some reason putting the index.php?$args /index.php?$args before /yourls-loader.php fixed it.
-Michael.

Hi again,
I was trying to get rid of the clunky ifs I had to put in to get both a public homepage and the redirects to work, and I thought that I must've just made a stupid mistake with the original configuration, as it seems like /yourls-loader.php would return 404 or similar if it didn't find the url, and would then pass to the next php file. However, it still tries to download the /yourls-loader.php. Any thoughts?
-Michael.

The configuration given here: https://github.com/YOURLS/YOURLS/wiki/Nginx-configuration as modified for proxying PHP to Apache does not work.

server {

  # Listen IPv4 & v6
  listen 80;
  listen [::]:80;

  # Optional SSL stuff
  listen              443              ssl;
  listen              [::]:443         ssl;
  ssl_certificate     example.com.crt;
  ssl_certificate_key example.com.key;

  # Server names
  server_name example.com www.example.com;

  # Root directory (NEEDS CONFIGURATION)
  root /path/to/files;

  # Rewrites
  location / {

    # Try files, then folders, then yourls-loader.php
    # --- The most important line ---
    try_files $uri $uri/ /yourls-loader.php;

    # PHP engine
    location ~ \.php$ {
      try_files      $uri =404;
      proxy_pass   https://example.com:8080; # Can be different
      include        proxy_params;
    }
  }
}

To make is work for such, I changed this

    # Try files, then folders, then yourls-loader.php
    # --- The most important line ---
    try_files $uri $uri/ /yourls-loader.php;

to

    # Try files, then folders, then yourls-loader.php
    # --- The most important line ---
    try_files $uri $uri/ /yourls-loader.php$request_uri;

Then in includes/functions.php, I changed function yourls_get_request as so:

return yourls_apply_filter( 'get_request', $request );

to

    /*  HACK for Nginx Proxying PHP to Apache: 
     *  Defaults on project site assume PHP-FPM fastcgi
     *  Therefore configs given do not work
     *
     *  This hack here removes "yourls-loader.php" from url if it exists
     *  Change in this function can coexist with PHP-FPM fastcgi setup
     *
     *  In Nginx conf, use:
     *      "try_files $uri $uri/ /yourls-loader.php$request_uri;"
     *      Instead of
     *      "try_files $uri $uri/ /yourls-loader.php;"
     *  If proxying to Apache
     */ 
    if( preg_match( "@yourls-loader\.php\/@", $request ) ) {
        $request = str_replace( "yourls-loader.php/", "", $request );
    }

    return yourls_apply_filter( 'get_request', $request );

I had to use
if (!-e $request_filename){ rewrite ^(.+)$ /yourls-loader.php?q=$1 last; }

instead of try_files $uri $uri/ /yourls-loader.php;

to make https://github.com/joshp23/YOURLS-IQRCodes work

@tofuSCHNITZEL. The try_files directive is preferred over !-e $request_filename. See https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#check-if-file-exists

See the note in my earlier comment suggesting try_files $uri $uri/ /yourls-loader.php$request_uri;. That needs an accompanying edit in includes/functions.php. For your case, you could consider try_files $uri $uri/ /yourls-loader.php?p=$request_uri;

@dakanji unfortunately even with your suggested functions.php edit none of the try_files directives work for me

@tofuSCHNITZEL The edit to functions.php goes specifically and only with the implementation of try_files that I had

Since if (!-e $request_filename){ rewrite ^(.+)$ /yourls-loader.php?q=$1 last; } works for you, then DO NOT edit functions.php and use:

try_files $uri $uri/ /yourls-loader.php?q=$request_uri;
or
try_files $uri $uri/ /yourls-loader.php?q=$uri;

That is, make no changes apart from swapping the if (!-e $request_filename)... line with one or the other of the try_files lines in this message.

I tried all of the different combinations. but none except the "if" works for me... I guess it has something to do with the plesk panel generated nginx directives....

Just a question...

Has anyone considered using the EasyEngine settings as a roadmap? At least for Ubuntu and Debian. The server settings for YOURLS and WordPress are nearly identical. A lot of people have put their time and effort into making that easy and workable.

_EasyEngine (ee) is a Python tool to easily manage your WordPress websites with Nginx, supported on Ubuntu and Debian Linux Distributions._

I'm getting ready to set up my first Nginx + https YOURLS MultiSite with WordPress MultiSite (EasyEngine) sharing the document root #2335 and am looking at Nginx server settings.

@PopVeKind Did you get it working? I am struggling right now with the conf. I can't get it to redirect.

@angelcosta - I currently have everything (except https) working on a shared hosting Apache. I currently have no access to Nginx (expecting a Linode within a week). Before I retired I used EasyEngine to build Nginx WordPress sites (Single and MultiSites), which I considered solid production sites.

Helpful Tips

  1. Get answers to the questions asked at https://github.com/PopVeKind/YOURLS/issues/3
  2. Remove all Plugins until you have the basic site working.

Help Offered

As part of my research into _Best Practices_, I am willing to help you get your conf. working.

  1. Navigate to https://github.com/PopVeKind/YOURLS/tree/multisite
  2. Open a new issue for your conf. file.
  3. Answer the questions asked at https://github.com/PopVeKind/YOURLS/issues/3
  4. Include what you have tried so far and what you expect it to do.

For people who need HTTPS configuration on nginx, here is my config

server {
    listen      80;
    listen      443 ssl;
    server_name YOURDOMAINHERE;
    root        /home/YOURLSPATH;

    access_log /home/YOURLSPATH/logs/access.log;
    error_log /home/YOURLSPATH/logs/error.log;


    index index.php;

    location / {
        try_files $uri $uri/ /yourls-loader.php;
        expires 14d;
        add_header Cache-Control 'public';
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_param HTTPS on;
    }
}

For any of you out there using EasyEngine, I managed to get it working by editing /etc/nginx/commmon/php.conf
there I added (commenting the existing line) only
location / { try_files $uri $uri/ /yourls-loader.php; expires 14d; add_header Cache-Control 'public'; }

@skeith - Thank You, that was a shove in the right direction.

Here's my ultimate goal.

  1. Anything coming in for redirection should work.
    Accept Both IP4 and IP6
    Accept Both HTTP and HTTPS
    Accept Both www. and no-www.
  2. Something for /admin/
    Accept Both IP4 and IP6
    Accept Only HTTPS
    Accept Only no-www.

The idea is to lock down the admin server, and speed up the redirection server (no multiple redirects)..
cu.te/abc may be _typed_ as www.cu.te/abc and different browsers may default to https or http

@angelcosta - Thanks for the specific info on the EasyEngine conf.

EasyEngine

A couple friends (acquaintances) in the EE camp are interested in the prototype YOURLS Plugins (described in the #2335 Patch):

  • YOURLS MultiSite Plugin (one install to manage several domains)
  • WordPress Plus YOURLS Plugin (working together without conflict, addressed in the document root directory - no subdirectory for either!)

If EE added support for these, it would be a nice boost for the YOURLS community.

Thanks everyone for your your contributions! 🎉 🙏
I've made a full review of the nginx configuration for YOURLS based on your suggestions, and updated the respective documentation. It's tested and approved on last versions of pieces of software involved.
Please take a look and let me know what are your thoughts! Thanks again! 👍

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ChrisChiera picture ChrisChiera  ·  5Comments

LaughterOnWater picture LaughterOnWater  ·  5Comments

youradds picture youradds  ·  3Comments

infotek picture infotek  ·  7Comments

lkuza2 picture lkuza2  ·  3Comments