NginxProxyManager / nginx-proxy-manager

Docker container for managing Nginx proxy hosts with a simple, powerful interface
https://nginxproxymanager.com
MIT License
22.01k stars 2.53k forks source link

Add GeoIP module #46

Open teodorch85 opened 5 years ago

teodorch85 commented 5 years ago

Hi! As I am noob with nginx is it possible to enable the GeoIP module so we can limit access also by location? https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-by-geoip/

Thank you!

Nuke142 commented 11 months ago

Can someone make complete instruction how to add geoip2 module in NPM docker?

gzxiexl commented 11 months ago

I'm waiting too

bohemtucsok commented 11 months ago

I'm waiting too

ThatCoffeeGuy commented 10 months ago

Yeah, same. Considering switching back to baremetal nginx only because of this. :(

❯ Starting nginx ...
nginx: [emerg] unknown directive "geoip_country" in /data/nginx/custom/http_top.conf:1

Is there an easy way to migrate from NPM docker to baremetal nginx? (fedora/ubuntu)

mixpc commented 6 months ago

+1 for the implementation of geoblock in nginx-proxy-manager

nbently commented 6 months ago

Edited 6/7/24 to be more concise & easy to read.

The PR above adds support for this geoip2 module: https://github.com/leev/ngx_http_geoip2_module.

The nginx_http_geoip2 module has been added to the base nginx configuration and can now be configured in Nginx Proxy Manager with the latest images. I'm not keen on providing a ton of support for this, but here's how I have my config set up.

You need the GeoLite2-City database from MaxMind. You'll need to create an account to download it. Keep in mind that this database is regularly updated and can become outdated quickly. It is outside the scope of this comment, but you may want to consider automating the download of the database into your configuration on a regular basis.

I have three custom files and the GeoLite2-City database mounted into the NPM container. I'm using bind mounts and have these files stored on my host machine in my configuration directory for NPM.

  1. GeoLite2-City.mmdb, MaxMind
  2. enable_ngx_http_geoip2_module.conf
  3. http_top.conf, NPM docs
  4. server_proxy.conf, NPM docs

Configuration

GeoLite2-City.mmdb

This is the IP location database from MaxMind. This is how IPs are matched with locations.

Mount the IP database into the container here: /data/geoip2db/GeoLite2-City.mmdb.

enable_ngx_http_geoip2_module.conf

The module is now included in NPM, but we need to enable it. This file enables the module in nginx's configuration.

Mount this file into the container here: /etc/nginx/modules/enable_ngx_http_geoip2_module.conf

File contents:

load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

http_top.conf

This file tells the module where the GeoLite2-City database is and configures an additional log format that includes the IP location data in each log line.

Mount this file into the container here: /data/nginx/custom/http_top.conf.

File contents:

geoip2 /data/geoip2db/GeoLite2-City.mmdb {
auto_reload 5m;
$geoip2_data_country_iso_code country iso_code;
$geoip2_data_city_name city names en;
}

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

server_proxy.conf

This file tells NPM to add the logging configuration you created above to each proxy host.

Mount this file into the container here: /data/nginx/custom/server_proxy.conf.

File contents:

access_log /data/logs/geoip.log geoip;

Feel free to tweak as it meets your needs, but this should get you up and running. This issue & #3334 should be able to be closed now.

Big thanks to @jc21 for getting the module merged so quickly.

GamerClassN7 commented 4 months ago

The PR above adds support for this geoip2 module: https://github.com/leev/ngx_http_geoip2_module.

The nginx_http_geoip2 module has been added to the base nginx configuration and can now be configured in Nginx Proxy Manager with the latest images. I'm not keen on providing a ton of support for this, but here's how I have my config set up.

I've got the GeoLite2-City database from MaxMind mounted in the container at /data/geoip2db/GeoLite2-City.mmdb.

I've got a conf file mounted in the container at /etc/nginx/modules/enable_ngx_http_geoip2_module.conf to enable the module.

load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

I've got a conf file mounted in the container at /data/nginx/custom/http_top.conf to configure the module, tell it where the GeoLite2 db is located, and configure a log format.

geoip2 /data/geoip2db/GeoLite2-City.mmdb {
auto_reload 5m;
$geoip2_data_country_iso_code country iso_code;
$geoip2_data_city_name city names en;
}

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

Finally, I've got a conf file mounted in the container at /data/nginx/custom/server_proxy.conf to instruct NPM to add a logging configuration to each proxy host.

access_log /data/logs/geoip.log geoip;

Feel free to tweak as it meets your needs, but this should get you up and running. This issue & #3334 should be able to be closed now.

Big thanks to @jc21 for getting the module merged so quickly.

Hello, would be possible to add more detail step by step tutorial and put it to documentation maybe ? I was not able to get it working in latest version of NPM :(

Thank in advance!

coltography commented 3 months ago

@GamerClassN7 did you ever get this figured out? Everywhere I look is not very noob friendly explanations of how to get this set up properly.

sbe-arg commented 3 months ago

Have a look at bunkerweb. Has geoblock included and other waf rules.

coltography commented 3 months ago

Have a look at bunkerweb. Has geoblock included and other waf rules.

Thank you very much. Looks pretty neat, I'm wondering if it works with crowdsec. Will look into it.

maboxx commented 3 months ago

What is bunkerweb? Maybe you have a link? Unfortunately I can't figure it out how it works and need more detailed instructions for dummies :-|

phyte22 commented 3 months ago

I somehow managed it with NginxProxyManager. I can try to write a little noob tutorial here at the weekend, as I am one myself ^^

maboxx commented 3 months ago

Wow that would be really great and I would be so grateful...... I have been waiting for this function in NPM for a long time and now I have no idea what to do :-(

phyte22 commented 3 months ago

I definitely wanted to whitelist countries, so I downloaded the country DB from https://dev.maxmind.com/geoip/geolite2-free-geolocation-data and put it in my Nginx folder. My Folder looks like this: image

you have to create 3 files (as described above) http_top.conf (config) enable_ngx_http_geoip2_module.conf (enables the geoip module) server_proxy.conf (for logging)

my http_top.conf looks like this: image in this example Netherlands is accepted. just add your whitelistes countries here

try to access your new log (/data/logs/geoip.log) and look if the country db works when you access your urls (-> look at the last two values of the log line)

if this looks correct then just go to your ngx-gui and set this advanced config to make it work on your desired proxy image

hope this helps in a way

maboxx commented 3 months ago

@phyte22 Thank you so much! I will be testing this very soon. I have NPM in Docker. I think my data folder is already set up “perstistent”. I'll have to check that again.

What I understood.

  1. Create 3 confs with the corresponding content. What content must the other two .conf have? enable_ngx_http_geoip2_module.conf server_proxy.conf

  2. Download the GeoLite2 Database: /data/geiip2db/GeoLite2-Country.mmdb

phyte22 commented 3 months ago

for 1. look at the post from https://github.com/NginxProxyManager/nginx-proxy-manager/issues/46#issuecomment-1971318240

There you can see the content

maboxx commented 3 months ago

Ok I have tested, unfortunately it does not work.

  1. At first I did it like you @phyte22 This is what my structure looked like:
    
    access/
    custom_ssl/
    database.sqlite
    enable_ngx_http_geoip2_module.conf
    geoip2db/
    GeoLite2-Country.mmdb
    http_top.conf
    keys.json
    letsencrypt-acme-challenge/
    logs/
    nginx/
    server_proxy.conf
Then I restarted the NPM docker container.
As soon as I configured the Advanced tab in NPM on a proxy host, the proxy host went offline.

if($allowed_country=no) { return 444; }


I have also not access to the log in /logs/geoip.log. The log is not created.

2. Then I did it exactly like in https://github.com/NginxProxyManager/nginx-proxy-manager/issues/46#issuecomment-1971318240 from @nbently 
My structure is then like this and I mounted also the conf in /etc/nginx/modules/enable_ngx_http_geoip2_module.conf

access/ custom/ http_top.conf server_proxy.conf custom_ssl/ database.sqlite geoip2db/ GeoLite2-Country.mmdb keys.json letsencrypt-acme-challenge/ logs/ nginx/



The result was the same. Do you or anyone else have any ideas?
phyte22 commented 3 months ago

What does it look like in your created files? Before you

if($allowed_country=no) {
    return 444;
}

you should first have a working log. The file geoip.log is not created under any circumstances? Then something fundamental does not seem to be working...

maboxx commented 3 months ago

Here the content from the files and once again my current structure:

access/
custom/
  http_top.conf
  server_proxy.conf
custom_ssl/
database.sqlite
geoip2db/
   GeoLite2-Country.mmdb
keys.json
letsencrypt-acme-challenge/
logs/
nginx/

http_top.conf

geoip2 /data/geoip2db/GeoLite2-City.mmdb {
auto_reload 5m;
$geoip2_data_country_iso_code country iso_code;
}

map $geoip2_data_country_iso_code $allowed_country {
   default: no;
   DE yes; # Germany
}

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

server_proxy.conf

access_log /data/logs/geoip.log geoip;

enable_ngx_http_geoip2_module.conf, mounted on /etc/nginx/modules/

load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

I also look to the usr/lib/nginx/mdules path if the .so file exists and it is there! But at the end the geoip.log is not created.

phyte22 commented 3 months ago

geoip2 /data/geoip2db/GeoLite2-City.mmdb {

you referenced the City DB. But you downloaded, as i did, the Country DB :D

maboxx commented 3 months ago

You 're right :-) I changed it and restart the container but same result. The geoip.log still not created :-( The configuration looks good I think but still not working.....

phyte22 commented 3 months ago

Hmm.. you can remove $geoip2_data_city_name out of the log. Additionally this are all my releated mounts for the NPM Container: /data/nginx/custom/server_proxy.conf /data/nginx/custom/http_top.conf /data/geoip2db/GeoLite2-Country.mmdb /etc/nginx/modules/enable_ngx_http_geoip2_module.conf

maybe you are missing something here? Are you running the latest version?

maboxx commented 3 months ago

I don't know what you mean with remove "$geoip2_data_city_name" out of the log? Can you explain again please? It looks the same for me as it does for you, I have the same mounts as you. The version is Version 2.11.2

See from inside the container:

http_top.conf

 _   _       _            ____                      __  __                                   
| \ | | __ _(_)_ __ __  _|  _ \ _ __ _____  ___   _|  \/  | __ _ _ __   __ _  __ _  ___ _ __ 
|  \| |/ _` | | '_ \\ \/ / |_) | '__/ _ \ \/ / | | | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
| |\  | (_| | | | | |>  <|  __/| | | (_) >  <| |_| | |  | | (_| | | | | (_| | (_| |  __/ |   
|_| \_|\__, |_|_| |_/_/\_\_|   |_|  \___/_/\_\\__, |_|  |_|\__,_|_| |_|\__,_|\__, |\___|_|   
       |___/                                  |___/                          |___/           
Version 2.11.2 (12d77e3) 2024-05-22 22:49:17 UTC, OpenResty 1.21.4.3, debian 12 (bookworm), Certbot certbot 2.10.0
Base: debian:bookworm-slim, linux/amd64
Certbot: nginxproxymanager/nginx-full:latest, linux/amd64
Node: nginxproxymanager/nginx-full:certbot, linux/amd64

[root@docker-a256c6b611ca:/app]# cat /data/custom/http_top.conf 
geoip2 /data/geoip2db/GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_data_country_iso_code country iso_code;
}

map $geoip2_data_country_iso_code $allowed_country {
   default: no;
   DE yes; # Germany
}

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

server_proxy.conf

[root@docker-a256c6b611ca:/app]# cat /data/custom/server_proxy.conf 
access_log /data/logs/geoip.log geoip;

GeoLite2-Country.mmdb

[root@docker-a256c6b611ca:/app]# ls /data/geoip2db/
GeoLite2-Country.mmdb

enable_ngx_http_geoip2_module.conf

[root@docker-a256c6b611ca:/app]# cat /etc/nginx/modules/enable_ngx_http_geoip2_module.conf 
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

The modules also exists:

[root@docker-a256c6b611ca:/app]# ls /usr/lib/nginx/modules/
ngx_http_geoip2_module.so
ngx_stream_geoip2_module.so

Is it perhaps not enough just to restart the container? Do I perhaps have to delete it completely first? I don't think so.

phyte22 commented 3 months ago

in my log_format I don't have “$geoip2_data_city_name” because we don't get the variable from the database.

apart from that, it's really weird... i didn't do more, if i remember correctly. Do you have any other NPM logs that might indicate that the geoip module could not be loaded or similar?

maboxx commented 3 months ago

I have now adjusted the log format, but it does not change anything.

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

This is the log when I restart the NPM docker container:

[6/1/2024] [4:22:19 PM] [Global   ] › ℹ  info      PID 166 received SIGTERM
[6/1/2024] [4:22:19 PM] [Global   ] › ℹ  info      Stopping.
❯ Configuring npm user ...
0
usermod: no changes
❯ Configuring npm group ...
❯ Checking paths ...
❯ Setting ownership ...
❯ Dynamic resolvers ...
❯ IPv6 ...
Enabling IPV6 in hosts in: /etc/nginx/conf.d
- /etc/nginx/conf.d/include/force-ssl.conf
- /etc/nginx/conf.d/include/proxy.conf
- /etc/nginx/conf.d/include/letsencrypt-acme-challenge.conf
- /etc/nginx/conf.d/include/block-exploits.conf
- /etc/nginx/conf.d/include/assets.conf
- /etc/nginx/conf.d/include/ssl-ciphers.conf
- /etc/nginx/conf.d/include/ip_ranges.conf
- /etc/nginx/conf.d/include/resolvers.conf
- /etc/nginx/conf.d/production.conf
- /etc/nginx/conf.d/default.conf
Enabling IPV6 in hosts in: /data/nginx
- /data/nginx/proxy_host/3.conf
- /data/nginx/proxy_host/6.conf
- /data/nginx/proxy_host/7.conf
- /data/nginx/proxy_host/18.conf
- /data/nginx/proxy_host/15.conf
- /data/nginx/proxy_host/2.conf
- /data/nginx/proxy_host/4.conf
- /data/nginx/proxy_host/24.conf
- /data/nginx/proxy_host/28.conf
- /data/nginx/proxy_host/29.conf
- /data/nginx/proxy_host/27.conf
- /data/nginx/proxy_host/5.conf
- /data/nginx/stream/1.conf
❯ Docker secrets ...
-------------------------------------
 _   _ ____  __  __
| \ | |  _ \|  \/  |
|  \| | |_) | |\/| |
| |\  |  __/| |  | |
|_| \_|_|   |_|  |_|
-------------------------------------
User:  npm PUID:0 ID:0 GROUP:0
Group: npm PGID:0 ID:0
-------------------------------------
❯ Starting backend ...
❯ Starting nginx ...
[6/1/2024] [4:22:24 PM] [Global   ] › ℹ  info      Using Sqlite: /data/database.sqlite
[6/1/2024] [4:22:25 PM] [Migrate  ] › ℹ  info      Current database version: none
[6/1/2024] [4:22:25 PM] [Setup    ] › ℹ  info      Logrotate Timer initialized
[6/1/2024] [4:22:25 PM] [Global   ] › ⬤  debug     CMD: logrotate /etc/logrotate.d/nginx-proxy-manager
[6/1/2024] [4:22:25 PM] [Setup    ] › ℹ  info      Logrotate completed.
[6/1/2024] [4:22:25 PM] [IP Ranges] › ℹ  info      Fetching IP Ranges from online services...
[6/1/2024] [4:22:25 PM] [IP Ranges] › ℹ  info      Fetching https://ip-ranges.amazonaws.com/ip-ranges.json
[6/1/2024] [4:22:25 PM] [IP Ranges] › ℹ  info      Fetching https://www.cloudflare.com/ips-v4
[6/1/2024] [4:22:25 PM] [IP Ranges] › ℹ  info      Fetching https://www.cloudflare.com/ips-v6
[6/1/2024] [4:22:26 PM] [SSL      ] › ℹ  info      Let's Encrypt Renewal Timer initialized
[6/1/2024] [4:22:26 PM] [SSL      ] › ℹ  info      Renewing SSL certs expiring within 30 days ...
[6/1/2024] [4:22:26 PM] [IP Ranges] › ℹ  info      IP Ranges Renewal Timer initialized
[6/1/2024] [4:22:26 PM] [Global   ] › ℹ  info      Backend PID 166 listening on port 3000 ...
[6/1/2024] [4:22:26 PM] [SSL      ] › ℹ  info      Completed SSL cert renew process
cruunnerr commented 3 months ago

@maboxx Hey there. Since you seem to be German, you might want to have a look at this site: https://decatec.de/home-server/nginx-besucher-mittels-geoip2-nach-laendern-blockieren-geoblocking/

This is pretty much the same as @phyte22 described. So maybe that helps you. Would be nice if you report your config if it works correctly.

Also think about not blocking your own LAN by adding something like:

geo $lan-ip {
default no;
192.168.1.0/24 yes; # your personal LAN
}

if ($lan-ip = yes) {
set $allowed_country yes;
}

if ($allowed_country = no) {
return 444;
}
maboxx commented 3 months ago

Thank you for the link but But I just don't think I understand it completely, I'm so sorry. The link only concerns me from the point "nginx-Konfiguration für GeoIP2" Because the geoip module is already integrated in NPM, isn't it?

nbently commented 3 months ago

@maboxx you might want to check to make sure your log_format configuration only includes variables present in the file you downloaded. I haven't tested this on the Country db, but theoretically it should still work, and it does seem like others have gotten it to work. FWIW the City db includes everything in the Country db but not the other way around. https://dev.maxmind.com/geoip/docs/databases/city-and-country#locations-files

Make sure your bind mounts are correct as well (e.g. the file on the host system is where you say it is).

I would suggest trying with my exact configuration first to see if that works and then tweaking it from there.

maboxx commented 3 months ago

@nbently I do it now exactly like you:

[root@docker-a256c6b611ca:/app]# ls -ltr /data/
total 516
-rw-r--r-- 1 root root   2190 Feb  9 20:30 keys.json
drwxr-xr-x 1 root root     22 Feb 15 10:04 letsencrypt-acme-challenge
drwxr-xr-x 1 root root    136 Feb 15 10:04 nginx
drwxr-xr-x 1 root root      0 Feb 18 22:31 access
drwxr-xr-x 1 root root    120 Feb 24 15:23 custom_ssl
-rw-r--r-- 1 root root 524288 Jun  2 07:19 database.sqlite
drwxr-xr-x 1 root root  12584 Jun  2 07:19 logs
drwxr-x--- 1 root root     60 Jun  8 07:28 custom
drwxr-x--- 1 root root     78 Jun  8 07:33 geoip2db

[root@docker-a256c6b611ca:/app]# ls -ltr /data/custom/
total 8
-rw-r----- 1 root root  39 May 29 07:26 server_proxy.conf
-rw-r----- 1 root root 437 Jun  8 07:23 http_top.conf

[root@docker-a256c6b611ca:/app]# ls -ltr /data/geoip2db/
total 55284
-rw-r----- 1 root root 50097859 Jun  7 15:49 GeoLite2-City.mmdb

[root@docker-a256c6b611ca:/app]# cat /data/custom/server_proxy.conf 
access_log /data/logs/geoip.log geoip;

[root@docker-a256c6b611ca:/app]# cat /data/custom/http_top.conf    
geoip2 /data/geoip2db/GeoLite2-City.mmdb {
auto_reload 5m;
$geoip2_data_country_iso_code country iso_code;
$geoip2_data_city_name city names en;
}

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

[root@docker-a256c6b611ca:/app]# ls -ltr /data/geoip2db/           
total 55284
-rw-r----- 1 root root 50097859 Jun  7 15:49 GeoLite2-City.mmdb

[root@docker-a256c6b611ca:/app]# cat /etc/nginx/modules/enable_ngx_http_geoip2_module.conf 
load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

I have now started Docker. How can I now check whether the module is loaded or working?

nbently commented 3 months ago

@maboxx if you're in the container you should now see a new log in /data/logs called geoip.log. That file will contain all of the new log data with the location data in each line. Make sure you have at least one proxy host set up and configured as well (otherwise there won't be any logs).

maboxx commented 3 months ago

@nbently

I am sad, there is no log :-(

[root@docker-a256c6b611ca:/data/logs]# ls -ltr geoip.log
ls: cannot access 'geoip.log': No such file or directory
[root@docker-a256c6b611ca:/data/logs]# 

I don't understand it. I do exactly what you do.

cruunnerr commented 3 months ago

@maboxx

I don't have much time at the moment. Will try to make you a noob-friendly HowTo till the weekend.

Just notice: I have my NPM docker folder in my home directory.

Basically I installed GeoIP like here: https://dev.maxmind.com/geoip/updating-databases

sudo add-apt-repository ppa:maxmind/ppa sudo apt update sudo apt install geoipupdate

I changed the DatabaseDirectory in /etc/GeoIP.conf: DatabaseDirectory /home/USER/NPM_DOCKER_FOLDER/GeoIP Also you need to insert your account-details here.

First try to download database: sudo geoipupdate should create you the database files in the /home/USER/NPM_DOCKER_FOLDER/GeoIP

Then created a crontab for updating database.

sudo crontab -e content:

# m h  dom mon dow   command
14 21 * * * geoipupdate

Then I created the files

_NPM_DOCKERFOLDER/modules/enable_ngx_http_geoip2_module.conf _NPM_DOCKERFOLDER/data/nginx/custom/http_top.conf _NPM_DOCKERFOLDER/data/nginx/custom/server_proxy.conf

My files look like this:

enable_ngx_http_geoip2_module.conf: load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;

http_top.conf:

geoip2 /data/geoip2db/GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_data_country_iso_code country iso_code;
}

map $geoip2_data_country_iso_code $allowed_country {
    default no;
    10.0.0.0/8 yes;
    192.168.0.0/16 yes;
    DE yes;

}

log_format geoip '$remote_addr - $remote_user [$time_local]'
           '"$request" $status $body_bytes_sent'
           '"$http_referer" $host "$http_user_agent"'
           '"$request_time" "$upstream_connect_time"'
           '"$geoip2_data_country_iso_code" "$allowed_country"';
           #'"$geoip2_data_city_name" "$geoip2_data_country_iso_code"';

server_proxy.conf:

if ($allowed_country = no) {
        return 444;
}
access_log /data/logs/geoip.log geoip;

Then I added the volume mounts to the docker-compose.yml:

version: "3"
services:
  app:
    image: jc21/nginx-proxy-manager:latest
    restart: always
    ports:
      - 80:80
      - 81:81
      - 443:443
    volumes:
      - ./config.json:/app/config/production.json
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
      - ./modules:/etc/nginx/modules
      - ./GeoIP:/data/geoip2db
    depends_on:
      - db
    environment:
    # if you want pretty colors in your docker logs:
    - FORCE_COLOR=1
  db:
    image: mariadb:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: "_PRIVATE_"
      MYSQL_DATABASE: "_PRIVATE_"
      MYSQL_USER: "_PRIVATE_"
      MYSQL_PASSWORD: "_PRIVATE_"
    volumes:
      - ./data/mysql:/var/lib/mysql

start the container:

sudo docker-compose up -d

Notice that I added the

if ($allowed_country = no) {
        return 444;
}

part inside the server_proxy.conf, since I couldn't get it worked with adding these lines in the webUI. But it worked pretty well. I tested accessing my proxy hosts via VPN from different countries, and only Germany got a response. :)

maboxx commented 3 months ago

Thank you very much @cruunnerr @nbently @phyte22 for your patience and effort, I will check again point by point as soon as I have time.

cruunnerr commented 3 months ago

Thank you very much @cruunnerr @nbently @phyte22 for your patience and effort, I will check again point by point as soon as I have time.

You're very welcome. Please keep in mind, that GeoIP-Blocking is a nice thing to have, but doesn't free your server from getting attacked. It is good for blocking bots and crawlers and surely prevents your proxy hosts from being inspected from several countries. But attackers often use bot nets and have several bots in different countries. So it kind of protects you from getting attacked from "everywhere". But I would definitely recommend you to also install crowdsec (or at least fail2ban) on your bare NPM-Server. Since crowdsec detects basically even before the packets reaches your NPM-Docker instance and can effectively protect against many kinds of attacks on vulnerabilities or exploits. Just imagine NPM or your OS has a vulnerability which can be attacked even before packets reach your Hosts or your NPM Docker instance. For example my crowdsec instance detected around 25 scenarios and blocked the IP's, just for today! For the hole June I have actually 473 blocked scenarios (85 of them from Germany, which even wouldn't have been blocked via GeoIP).

Just think about it ;)

nbently commented 3 months ago

@maboxx can you show us where you have the bind mounts configured?

maboxx commented 3 months ago

I probably won't have time to go through the whole thing again until the weekend. @cruunnerr Thank you very much for the tips. My constellation is such that my NPM runs on a virtual machine with hardened archlinux. Docker runs rootless there. NPM is my entrance to the network and then forwards to another virtual machine with my Nextcloud. This VM is also hardened and fail2ban is also running there. I may still have to take care of fail2ban on my NPM VM.

@nbently I don't quite understand what you mean because my mounts work otherwise I couldn't access them from inside the container? Here is my stack that I deploy via Portainer.

version: '3'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy
    restart: always
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
      - '993:993'
      #- '587:587'
    volumes:
      - nginx-proxy-data:/data
      - nginx-proxy-letsencrypt:/etc/letsencrypt
      - nginx-proxy-modules:/etc/nginx/modules

volumes:
  nginx-proxy-data:
    name: nginx-proxy-data
  nginx-proxy-letsencrypt:
    name: nginx-proxy-letsencrpyt
  nginx-proxy-modules:
    name: nginx-proxy-modules
nbently commented 3 months ago

@maboxx that's what I was wondering, I see you're using volumes and not bind mounts. Theoretically that should work no problem but I bet that's where the issue is. Probably something permission related if I had to guess.

What happens if you create the geoip.log file manually (just an empty file)? I'd also check to make sure all the files you created have the same permissions as everything else & that the user running nginx has access to them.

maboxx commented 3 months ago

Ok but when I compare the permissions from my files with the permissions of your file which seen above in your thread they are the same. What can be different between using bind mounts or volumes? What is exactly the difference and how can I set bind mounts? I think another difference to your configuration is that my docker runs "rootless" but this should normally also not a problem.... I created the geoip.log manually. After restart and one day after now the .log have 0 bytes. Maybe I just clone my VM and install NPM exactly like you did without rootless to see if it works? It remains strange. I don't think anything is configured wrong. Rootless and no bind mount should not be a problem.

@cruunnerr Little digression about crowdsec. I would like to install crowdsec to secure NPM (docker). How exactly did you install and configure it? Do you have any links? Did you also install crowdsec as a docker or directly on the machine? How do I connect Crowdsec to the NPM Docker so that it secures NPM? Ideally, I would also like to completely back up the local machine at the same time, not just NPM?

XDark187 commented 1 month ago

Have a look at bunkerweb. Has geoblock included and other waf rules.

Great Alternative.

maboxx commented 3 weeks ago

@XDark187 Thanks for the tip. I still have no idea what exactly Bunkerweb is. I have heard of it but despite research I don't understand it exactly. Bunkweb is probably much more than "just" a proxy manager.

XDark187 commented 3 weeks ago

@XDark187 Thanks for the tip. I still have no idea what exactly Bunkerweb is. I have heard of it but despite research I don't understand it exactly. Bunkweb is probably much more than "just" a proxy manager.

Bunkerweb is a reverse proxy but with a lot of security features to protect your services by default, one of these security features is geoIP blocking and stopping brute force attacks and stopping bots, all security features are just toggles that you can enable or disable if you don't need them.

NPM requires so much work just to enable geoip blocking.

NPM is easier but less secure and bunkerweb is more secure but requires a bit of time to get it fully setup. IMO it's 100% worth it.

If you don't want to bother with NPM or Bunkerweb the easiest way is to use geoIP blocking with Cloudflare.