How to secure xenforo with Nginx

Easy... basically the same way you are doing in your example for the admin.php. Here is what I use:
Code:
location /install {
        auth_basic "Administrator Login";
        auth_basic_user_file /my/secret/sauce/my.pass.word;
        index index.php index.html index.htm;
        }
You don't need that, just apply a maintenance filter. When your site is in maintenance, only you can access that directory. Otherwise, everyone will get a 404.
https://www.axivo.com/community/install/
https://www.axivo.com/community/install/index.php
Code:
[root@chronos community]# pwd
/var/www/axivo.com/community
[root@chronos community]# ls -lah install
total 40K
drwxr-xr-x. 4 root root 4.0K Nov  6 19:27 .
drwxr-xr-x. 8 root root 4.0K Nov  6 19:38 ..
drwxr-xr-x. 2 root root 4.0K Nov  6 19:38 data
-rw-r--r--. 1 root root  624 Nov  6 19:27 index.php
-rw-r--r--. 1 root root  15K Nov  6 19:27 install.css
-rw-r--r--. 1 root root 3.5K Nov  6 19:27 language_en.php
drwxr-xr-x. 2 root root 4.0K Nov  6 19:38 templates
 
Last edited:
I can't get this conf work for protect my admin.php

Code:
location ~/admin\.php$ {
auth_basic "Administrator Login";
auth_basic_user_file /usr/share/nginx/html/.htpasswd;
root /usr/share/nginx/html;
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_read_timeout 300;
include fastcgi_params;
}

There is no htpasswd login form.

Any suggestion?
 
Last edited:
I can't get this conf work for protect my admin.php

Code:
location ~/admin\.php$ {
auth_basic "Administrator Login";
auth_basic_user_file /usr/share/nginx/html/.htpasswd;
root /usr/share/nginx/html;
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_read_timeout 300;
include fastcgi_params;
}

There is no htpasswd login form.

Any suggestion?
I would like to know this as well. I never could get nginx to password protect a file or director.
 
Alright, you can't use "short answers" on me when it comes to nginx. lol

(There is a reason why I defer to people such as @MattW for nginx)

What does the final version look like?
Ouch. Sorry. I'm in hurry. :D

Here is my /sites-enabled/default

Code:
server {   
listen 80 default_server;   
listen [::]:80 default_server ipv6only=on;

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

# Make site accessible from http://localhost/   
server_name localhost;

location ~/admin\.php$ {
auth_basic "Staff Only";       
auth_basic_user_file /some/path/outside/root/htpasswd;
root /usr/share/nginx/html;       
try_files $uri =404;       
fastcgi_pass unix:/var/run/php5-fpm.sock;       
fastcgi_index index.php;       
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;       
include fastcgi_params;   
}

location / {       
# First attempt to serve request as file, then       
# as directory, then fall back to displaying a 404.
...
Here's mine. :)

I know it's bad to have root inside a block when you are already had root. But... anyone know a better way?
 
I can't get this conf work for protect my admin.php

Code:
location ~/admin\.php$ {
auth_basic "Administrator Login";
auth_basic_user_file /usr/share/nginx/html/.htpasswd;
root /usr/share/nginx/html;
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_read_timeout 300;
include fastcgi_params;
}

There is no htpasswd login form.

Any suggestion?

PHP:
location ~/admin\.php$ {
auth_basic "Staff Only";
auth_basic_user_file /some/path/outside/root/htpasswd;
root /usr/share/nginx/html;
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

Don't mind me.... I'm just quoting for future reference :D
 
This one works fine for me (on 7 forums - 4 myBB with some modifications to it)... but since we are talking xenForo. There is a rewrite for robots.txt in it since I use the sitemap add-on.
Code:
server {
    listen 80;
    server_name www.justsayapple.com justsayapple.com www.justsayapple.net justayapple.net;
    return 301 http://sayapple.com$request_uri;

}

server {
    listen 80;
    server_name www.apple4me.net apple4me.net;
    return 301 http://sayapple.com$request_uri;
}

server {
    listen 80 default_server;
    server_name sayapple.com;

rewrite ^/(.*)/favicon.ico$ /favicon.ico last;
    error_log /var/log/nginx/apple-error.log warn;
    access_log /var/log/nginx/apple-access.log;
    root /var/www/apple4me;

location /symlinktophpmyadmin {
    auth_basic "Restricted";
    auth_basic_user_file /my/secret/sauce/ht.password;
    root /usr/share/;
    index index.php index.html index.htm;
    location ~ ^/symlinktophpmyadmin/(.+\.php)$ {
    try_files $uri =404;
    root /usr/share/;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME
    $document_root$fastcgi_script_name;
    include /etc/nginx/fastcgi_params;
    }
    location ~* ^/symlinktophpmyadmin/(.+\.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt))$
          {
        root /usr/share/;
        }
    }
    location /SymLinkToPhpMyAdmin {
    rewrite ^/* /symlinktophpmyadmin last;
    }


location /images/ {
expires max;
}

location /nginx_status {
                stub_status on;
                access_log  off;
                allow 127.0.0.1;
                allow 199.48.164.104;
                allow 24.49.69.204;
                deny all;
        }


location /install {
        auth_basic "Administrator Login";
        auth_basic_user_file /my/secret/sauce/ht.password;
        }

location = /admin.php {
    auth_basic "Just Say Apple Administrator Login";
    auth_basic_user_file /my/secret/sauce/ht.password;
    try_files $uri =404;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME
    $document_root$fastcgi_script_name;
    include /etc/nginx/fastcgi_params;
    }


    location / {
## Deny certain User-Agents (case insensitive)
    ## The ~* makes it case insensitive as opposed to just a ~
    if ($http_user_agent ~* (Baidu|Ahrefsbot|Morfeus|ZmEu|Baiduspider|Jullo|Yandex|Sogou) ) {
        return 444;
    }
            #This sends everything through index.php and keeps the appended
            #query string intact.
            try_files $uri $uri/ /index.php?$uri&$args;
            index index.php index.html index.htm;
          rewrite /(robots.txt)$ /robots.php last;

    #gzip it, gzip it good
      gzip                    on;
      gzip_http_version      1.1;
      gzip_vary              on;
      gzip_min_length        1100;
      gzip_buffers            64 8k;
      gzip_comp_level        2;
      gzip_proxied            any;
      gzip_types              image/png image/gif image/jpeg image/jpg text/xml text/plain text/css application/json application/x-javascript application/vnd.ms-fontobject application/x-font-
ttf font/opentype application/xml application/rss+xml application/atom+xml application/rdf+xml;
      gzip_disable "MSIE [1-6]\.(?!.*SV1)";
        }


      # use fastcgi for all php files
        location ~ \.php$ {
        # Zero-day exploit defense.
        # http://forum.nginx.org/read.php?2,88845,page=3
        try_files $uri /index.php =404;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_intercept_errors on;
        fastcgi_ignore_client_abort off;
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 180;
        fastcgi_read_timeout 180;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;


        }

# Feed
        location ~* \.(?:rss|atom)$ {
            expires 1h;
            add_header Cache-Control "public";
    }

# Media: images, icons, video, audio, HTC
        location ~* \.(?:jpg|jpeg|gif|png|ico|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
            expires 1M;
            access_log off;
            add_header Cache-Control "public";
    }

# CSS and Javascript
        location ~* \.(?:css|js)$ {
            expires 1y;
            access_log off;
            add_header Cache-Control "public";
    }

# WebFonts
# If you are NOT using cross-domain-fonts.conf, uncomment the following directive
        location ~* \.(?:ttf|ttc|otf|eot|woff|font.css)$ {
            expires 1M;
            access_log off;
            add_header Cache-Control "public";
    }

        location /internal_data {
                location ~ \.(data|html|php)$ {
                        internal;
                }
                internal;
        }
        location /library {
                location ~ \.(default|html|php|txt|xml)$ {
                        internal;
                }
                  internal;
        }

        # deny access to apache .htaccess files
        location ~ /\.ht
        {
        deny all;
    }
}
 
Last edited:
@Tracy Perry

I see you use symlink to serve phpMyAdmin. Why? I think we can just put phpMyAdmin inside somewhere in root and protect it with htpasswd. Or is not secure enough?
 
@Tracy Perry

I see you use symlink to serve phpMyAdmin. Why? I think we can just put phpMyAdmin inside somewhere in root and protect it with htpasswd. Or is not secure enough?
Obscurity by obfuscation. You are always seeing attempts to hit /phpMyAdmin in logs... this way they have to have the secret decoder ring to know the rewrite name.

At one time the symlink was supercalifragilisticexpialidocious-y0uw1sh. :p
 
I can't get this conf work for protect my admin.php

Code:
location ~/admin\.php$ {
auth_basic "Administrator Login";
auth_basic_user_file /usr/share/nginx/html/.htpasswd;
root /usr/share/nginx/html;
try_files $uri =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_read_timeout 300;
include fastcgi_params;
}

There is no htpasswd login form.

Any suggestion?

For one you should not be specifying root in a location block. There's absolutely zero reason to do that. The web root should be specified in the server block for each vhost.

Did you restart Nginx after adding the auth_basic parameter? You have to reload or restart Nginx after every config change. The method will vary depending on your linux distro and how you installed Nginx.
 
For one you should not be specifying root in a location block. There's absolutely zero reason to do that. The web root should be specified in the server block for each vhost.

Did you restart Nginx after adding the auth_basic parameter? You have to reload or restart Nginx after every config change. The method will vary depending on your linux distro and how you installed Nginx.
Well...
I know it's bad to have root inside a block when you are already had root. But... anyone know a better way?
Do you had any better configuration? Anyway it's Debian.
 
Well...

Do you had any better configuration? Anyway it's Debian.

The better way is to just not have root specified in your location block. You appear to already have it in your server block so you can just remove that line. Are you running into an issue when you don't have root in your location block?

Still not clear why HTTP auth isn't working for you. All Debian repo Nginx packages have the basic_auth module installed and Nginx wouldn't start with an improper config. It might have to do with the regex. Nginx matches the most specific location block first which I believe your admin location block should do, but when you start using fuzzy matching with regex things can get complicated. If you have another location block which somehow matches the admin pages more specifically then you're not going to be serving admin through that location block.

I don't have my admin panel HTTP auth protected but I do use HTTP auth with Nginx for a lot of other purposes and it works perfectly for me.
 
@Tracy Perry

I see you use symlink to serve phpMyAdmin. Why? I think we can just put phpMyAdmin inside somewhere in root and protect it with htpasswd. Or is not secure enough?

I *never* have phpmyadmin (or any similar admin tools) on the same domain as any of my public sites.
Always use a separate direct IP address or domain that is not publicly used for serving www
IMHO.
 
I *never* have phpmyadmin (or any similar admin tools) on the same domain as any of my public sites.
Always use a separate direct IP address or domain that is not publicly used for serving www
IMHO.
Yeah - I've thought about that. I've got to get with my hosting provider to get a couple of more IP's (last time they gave me a /28 range - but that was for a ProxMox server and at no additional cost).
 
Top Bottom