You are currently viewing GeoIP: Nginx

GeoIP: Nginx

GeoIP-tietoa, eli mihin maahan IP-osoite kohdistuu, voidaan käyttää sisällön kohdentamiseen tai blokkauksiin. Itse käytän sitä nimenomaan estoihin, jolloin määrätyt maat eivät pääse palomuurista läpi ja kuormitus kevenee huomattavasti. Servereiden ja sivustojen suurin ongelma kun ei ole WordPressien raskaus tai aitojen kävijämääräen suuruus, vaan täysin turhat SEO-botit sekä aukkoja etsivät koputtelijat. Mutta maakielto on vaihtoehto vain silloin kun tietää, että jostain maasta ei tule potentiaalisia kävijöitä. Tämä sivusto ei ole globaali, joten Kiinan estäminen ei ole ongelma. Mutta ulkosuomalaisia on ympäri maapallon, joten asioita on laitettava vaakakuppiin.

Geotiedolla voidaan tehdä kohdennus myös kaupunkitasolla, mutta se on puhdasta ajanhukkaa. Jokainen tietää (tietäähän?), että IP-osoitteet vaihtuvat ja paikallinen kohdennus osuu sinne missä samaa IP-osoitetta on viimeksi käytetty. Asun Vihdissä, mutta koska Elisan mobiiliverkko kiertää Uudellamaalla Helsingin kautta, niin lähes aina minun väitetään olevan Helsingissä. Paitsi puhelimen viimeisen päivitysbuutin jälkeen, jolloin IP taas vaihtui, ja oli väitetysti Jyväskylässä.

VPN-palvelut sotkevat kuviota lisää, mutta nimenomaan maatunnistuksen myötä. Suomalainen kävijä voikin kohdentaa itsensä vaikka Belizeen ihan riippuen mitä palvelua hän on aiemmin yrittänyt vedättää – ollaan rehellisiä, se on yleisin syy käyttää VPN:ää, ei julkisten wifi-hotspottien pelko.

Jossain on suodatettava

Minulla ensimmäinen IP-suodatus tapahtuu palomuurissa. UFW blokkaa pahimmat roskapostittajamaat, poislukien USA:n, Saksan ja Alankomaat. Ne on lähes pakko sallia ja tehdä siivous vaikka user agentin perusteella, koska liian monen (lue: kaikkien) hyödyllisen palvelun IP-osoitteet kohdistuvat tuohon kolmikkoon. Sen lisäksi niin Nginx kuin Varnish vahtivat url-kyselyjä ja kun vastaan tulee kielletty, niin Fail2ban hoitaa bannaamisen.

Tuossa on kuitenkin selvä heikkous. Kun Google, tai useimmiten Bing, päättää jostain täysin mystisestä syystä yrittää indeksoida kiellettyä urlia, niin niiden IP-osoitteet päätyvät Fail2bannin käsiin. Tai kun itse töpeksii ehtojen tai regexin kanssa, niin saa bannattua suunnilleen jokaisen suomalaisen IP-osoitteet. Been there jne. Googlen ja Bingin kohdalla maatunnistus ei auta, vaan on yritettävä pärjätä user agenttien kanssa, mutta käyttäjien kohdalla maatunnistuksella ennen urlin tarkastusta voi estää bannin ja käyttäjä saa virhetilanteessan vastaan tutun turvallisen, ja ärsyttävän, kaatuneen sivuston.

Koko ajan palataan samaan: maatunnistus kulkee käsi kädessä user agentin ja urlin kanssa. On mahdotonta pärjätä vain yhdellä suodattavalla arvolla.

UFW ja geo-tunnistus on ehdottomasti tehokkain. Mutta se on myös hankalimmin säädeltävä. Kyseessä on on/off, jonka voi unohtaa toimimaan yksikseen ja sitten vain toivoo, että geo-tunnistuksen tarvitsemat whitelistatut IP-listat pysyvät ajantasalla. Mutta jos haluaakin jostain syystä muuttaa jotain, tai ohittaa maatunnistuksen, niin UFW ja sen takana luuraava iptables vaativatkin enemmän töitä.

Vaihtoehdoksi nousee kaikkien päästäminen palomuurista läpi ja aloittamalla apuharventaminen ensin webserverillä. Loppusäädöt voi tehdä reverse proxyssä ja siinä työssä Nginx + Varnish on ykkönen.

Lähtöasetelma

Ohjeet ovat virtuaaliserverille, joka pyörii Ubuntulla.

  • Nginx hoitaa SSL:n ja HTTP/2:en, sekä suorittaa ensimmäiset ehdottomat suodatukset
  • Varnish hoitaa cachen lisäksi ehdolliset suodatukset
  • Apache2 tarjoilee (suurimman osan) sivustot siltä osin, kun asioita ei löydy cachesta tai niitä ei voida välimuistittaa; pyrkimys olisi, että Apache2 ei oikeastaan tekisi yhtään mitään

Jos sinulla on keulilla Apache2, niin toivotan jaksamista Googlen parissa. Nämä ohjeet perustuvat Nginxin käyttöön, enkä tiedä miten sama asia tehdään Apachessa. Mutta itse asiaa penkoessani törmäsin ohjeisiin, joiden mukaan onnistuisi.

VPS on DigitalOceanin hallussa. En ota kantaa onko se hyvä vai huono ja varmasti tehokkaampiakin löytyy. Otan kuitenkin kantaa: minulle DigitalOcean tarjoaa sen mitä tarvitsen sillä hinnalla, jonka kykenen maksamaan. Kun aletaan vertailemaan hinta/laatu-suhdetta, niin DigitalOceania on hankala haastaa. Joten kysymys minne palvelunsa sijoittaa keskittyy oikeastaan kahteen asiaan: kuinka paljon tehoja aidosti tarvitsee ja riittääkö rahat sen maksamiseen.

Oletko webhotellissa? Olen pahoillani, mutta sinulla on työkalut aika vähissä, eikä mikään tämän jutun neuvoista auta sinua. Jos sivustosi on WordPressissä, niin cachen saat hoidettu WP Rocketilla, mutta loput sitten jääkin haaveiden tasolle. Toki osa turvallisuudella mainostavista lisäosista tekee osan työstä, mutta pääsääntöisesti niiden hyöty on nolla. Tai negatiivinen, koska ne paisuttavat WordPressiä sekä lisäävät kuormaa tietokannan suuntaan.

Tehokas webhotelli maksaa vuodessa satasen verran. Muutamalle sivustolle, verkkokaupalle ja parille foorumille, joissa pyörii päivässä 2000 – 5000 ihmistä moinen tehokkuus ei riitä. VPS maksaa noin satasen kuukaudessa, mutta sen pystyy painamaan 40 euroon. Ei webhotellien halvempi hinta ole pelkästään hinnoittelusta johtuva, vaan että karsitaan asioita. Jos innostut siirtymään virtuaaliserverille, niin millään 5 – 10 euron kuukausihinnalle ei sitten pärjää kuin kokeiluhommissa.

Olen tehnyt kaiken neuvomani. Se, että onko moinen käytössä enää siinä vaiheessa kun sinä luet tätä, on oma juttunsa. Mikään ei myöskään takaa, että ohjeet toimivat vielä ensi viikollakin. Asiat kun tuppaavat muuttumaan. Varsinkin geo-tiedot tarjoava MaxMind on tunnettu siitä, että he muuttavat aika ajoin systeemejään niin, että kaikki vanhat ohjeet ja neuvot kaatuvat kerta heitolla roskakoriin.

Itse teen työt aina rootin roolissa. Joten jos sinulla on oma käyttäjä, niin arvo sudo tai su sopiviin paikkoihin.

Nginx vai Varnish

Geo-tunnistuksen voi tehdä joko Nginxissä heti tai vasta Varnishissa. Ero on siinä, että Nginx vaatii käännettäväksi oman moduulin, ja Varnishille on käännettävä oma VMOD. Minä tein sen alunperin Nginxin kautta, mutta valinta perustui vain ja ainoastaan niinkin tylsään syyhyn, että löysin Nginxin ohjeet ensin.

En tiedä kumpi tapa olisi järkevämpi. Jos käytössä on useampi sivusto, eikä jokainen kierrä Varnishin kautta, niin Nginxillä GeoIP-tieto saadaan kaikille – käyttää sitä tai ei. Ja joka tapauksessa geo-tieto viedään Varnishille, mutta erillisellä headerilla. Varnishilla taasen saadaan ehkä hieman vähennettyä muistin käyttöä, kun Nginx ei tee kaikkea kaikille (en todellakaan tiedä onko noin).

Valintaan saisi vaikuttaa sekin, että kumpi on helpompi pitää päivityksissä ehjänä. Mutta koska en ole tätä kirjoitettaessa kummankaan kanssa joutunut asiaa pohtimaan, niin en ota kantaa. Oma käsitys kuitenkin on, että molemmissa laajennoksissa joutuu päivitykset tekemään erikseen käsin, joten siltä osin helpotusta ei saa. Mutta minulla on aiemmin mennyt Varnishilla asioita rikki sen päivittyessä, niin olen ehkä einen säikky VMOD-ajatukselle. Puhumattakaan siitä, että aika usein VMOD:n käännös ei todellakaan suju niin jouhevasti kuin ohjeet antaisivat ymmärtää.

Tekee maasuodatuksen sitten kummassa tahansa, niin on syytä oivaltaa sinänsä yksinkertainen perusasia. Geo-suodatus koskee silloin vain ja ainoastaan webserveriä. Se ei vaikuta SSH:n tai sähköpostipalvelimen murtoyrityksiin. Jos haluaa suojata nekin maatasolla, niin ainoa vaihtoehto on rakentaa estot ja sallimiset iptablesiin – kattavat säännöt ovat nimenomaan palomuurin tehtäviä.

GeoIP-tunnistus Nginxiin

Ensin täytyy kertoa Nginxille, että se saa selvittää IP-osoitteen maan. Se ei valitettavasti onnistu pelkällä conf-tiedoston muutoksella, vaan joudutaan käännöshommiin. Se on prosessina helppo, jos kaikki tarpeellinen on asennettuna. Jos ei ole, niin saa geneerisen virheilmoituksen, joka ei ainakaan minun elämääni helpottanut.

Vaadittava moduuli voidaan tehdä aktiivisena, jolloin sitä täytyy erikseen kutsua nginx.conf tiedostossa. Tai sitten se voidaan kääntää passiiviseksi, jolloin GeoIP ymmärtääkseni leivotaan toiminnallisuudeksi Nginxin sisään ja se olisi käytössä suoraan koko ajan, samalla tavalla kuin vaikkapa SSL. Minä valitsin ratkaisuksi aktiivisen, koska haluan vapaammat kädet päättää mitä on päällä ja koska.

  • Otetaan käyttöön MaxMindin repo:
add-apt-repository ppa:maxmind/ppa
  • Kerrotaan päivitykset järjestelmälle tutulla tavalla:
apt update
  • Asennetaan MaxMindin haluamat:
apt install libmaxminddb0 libmaxminddb-dev mmdb-bin
  • Siirry haluamaasi hakemistoon, jonne voi ladata väliaikaisesti tarvittavat tiedostot. Itse käytän /tmp hakemistoa, koska ne häviävät sieltä itsestään ajan myötä.
cd /tmp
  • Ladataan käännettävä Nginxin kaipaama moduuli. Huomioi versionumero. Tarkista Githubista, että se on tuore. Päivitystahti on kylläkin version suhteen erittäin hidas, joten esimerkki saattaa toimia sellaisenaan pidempään.
wget https://github.com/leev/ngx_http_geoip2_module/archive/3.3.tar.gz
  • Puretaan tar-paketti:
tar zxvf 3.3.tar.gz
  • Tarkista käyttämäsi Nginxin versio komennolla nginx -v ja lataa sitä vastaava lähdekoodi. Tätä kirjoitettaessa se oli 1.18.0.
wget https://nginx.org/download/nginx-1.18.0.tar.gz
  • Puretaan se:
tar zxvf nginx-1.18.0.tar.gz
  • Siirrytään paketin purussa luotuun hakemistoon:
cd nginx-1.18.0
  • Kääntäminen onnistuu vain jos kaikki tarvittava on asennettuna serverille. Ainakin nämä olisi oltava asennettuna:
apt install libpcre3 libpcre3-dev
  • Tuo ei vielä riitä, vaan järjestelmä on päivitettävä uudestaan:
apt install && apt dist-upgrade -y
  • Tehdään tarvittava moduli. Muuta komennossa moduulin lähdekoodin hakemisto oikeaksi.
./configure --with-compat --add-dynamic-module=/tmp/ngx_http_geoip2_module-3.3
make
make module

Jos saat virheilmoituksen make: *** No rule to make target 'modules'. Stop. niin se tarkoittaa, että sinulta puuttuu joku tarvittava paketti. Ehkä onnistut löytämään mikä se on. itse taistelin tuon kanssa aika kauan.

  • Siirretään tehty moduuli Nginxin haltuun:
cp objs/ngx_http_geoip2_module.so /etc/nginx/modules-available/
  • Jotta noudatettaisiin Nginxin tapoja, niin tehdään symbolinen linkki (tätä ei aidosti vaadita, onpahan vaan vastaavaa logiikkaa kuin virtual hostien kanssa):
ln -s /etc/nginx/modules-available/ngx_http_geoip2_module.so /etc/nginx/modules-enabled/

Nyt tarvitaan vielä varsinainen GeoIP-tietokanta. Se ladataan MaxMindin sivustolta ja siihen vaaditaan rekisteröityminen.

MaxMind ja GeoIP2

GeoIP-palveluja on kourallinen. Ilmaisia, joissa on myös toimiva päivitys sekä tapa saada IP-tunnistus toimimaan, on vain yksi: MaxMind. Siksi käytännössä kaikki ohjeet perustuvat MaxMindin käyttöön.

Kun googletat GeoIP2-estämistä, niin saat kohtuullisen paljon neuvoja. Kun yrität saada asioita toimimaan niiden avulla, niin yksikään neuvo ei toimi. Syynä on jokin omituinen lakitekninen vääntö Kalifornian osavaltion ja MaxMindin välillä, jossa on häivähdys meikäläistä GDPR:ää. Sen takia MaxMind vaatii nykyään rekisteröitymistä, joka rikkoi suurimman osan neuvoista.

Jokainen ennen vuotta 2019 kirjoitettu ohje perustuu mahdollisuuteen ladata Geo-tietokannat CVS-muodossa suoraan MaxMindilta. Sitten tuli muutos ja MaxMind alkoi vaatimaan API:a, jota kutsutaan salasanaksi, mutta tietokannat olivat ilmaisien suhteen silti käytössä geneerisellä salasanalla. Suurin muutos oli, että CSV-muoto hävisi ja ladattavaksi tuli mmdb-tietokanta ja jokainen tekstipohjaiseen CVS-kantaan perustuneet ohjeet hajosivat. Vuoden 2020 aikana tuli uusi muutos, joka edellytti todellista aitoa käyttäjärekisteröintiä ja se sitten rikkoi loputkin ohjeet. Sittemmin CVS-muoto palasi, mutta en ole kokeillut onko sen rakenne sellainen, että vanhat ohjeet toimisivatkin taas.

Pienellä soveltamisella asiat saa kuitenkin toimimaan, eikä tekemiseen tarvita mitään sen kummempaa teknistä osaamista. Tekstitiedostoja täytyy osata muokata ja kopioida pari tiedostoa, mutta ei sen kummallisempaa.

Ongelma on siinä, että GeoIP2-kysymys on edelleenkin muutoksessa, eikä mikään takaa, että nämäkään ohjeet toimivat enää sinun lukiessasi. Itseasiassa 2022 tai 2023 on taas tulossa suurempi muutos.

GeoIP2-tietokanta

  • Koska ollaan ylipäätään liikkeellä aika yleishyödyllisen aiheen parissa, niin kannattaa tehdä pieni sivuhyppu ja asentaa GeoIP-tietokanta, joka kertoo maat virtuaaliserverillekin:
apt install geoip-bin geoip-database
  • Voit testata toiminnan komennolla:
geoiplookup 8.8.8.8

Jos saat vastaukseksi, että kyseessä on US, United States niin homma toimii.

Tuota ei sinällään tarvita Nginxin GeoIP-toiminnan kanssa, mutta samalla sen asentaa. Moni muu asia käyttää tai voisi käyttää sitä.

Sitten tarvitset päivitykset tietokantaan, koska IP-maailma muuttuu koko ajan. Tapoja on muutama, mutta käytännössä on käytettävä MaxMindin palvelua. Sinne on pakko rekisteröityä, mutta se on urakkana helpoin ja jos/kun sinulle riittää ilmaiset, kerran viikossa päivitettävät ja vain noin 98 % oikeassa olevat tietokannat, niin rekisteröinti ei maksa mitään.

  • Aloitetaan asentamalla ensimmäiseksi GeoIP2-tietokannan päivitysohjelma:
apt install geoipupdate

geoipupdate tarvitsee oman conf-tiedoston, josta se löytää MaxMindin käyttäjätunnuksen, salasanan sekä mitkä tietokannat ladataan. Sitä varten tarvitset tunnukset. Tili on pakko tehdä, jos aikoo ylipäätään tehdä minkäänlaista geoip-estoa, joten aidosti tässä ei oikein ole valinnanvaraa. Perustietokannat ovat ilmaisia, mutta jos haluat tarkempaa, niin joudut maksamaan.

  • Luo tili MaxMindiin osoitteessa https://www.maxmind.com/en/geolite2/signup. Anna pyydetyt tiedot. Sinun täytyy täyttää myös yrityksen nimi ja jos sellaista ei ole, niin keksi jotain tai laita nimesi.
  • Saat vahvistussähköpostin. Klikkaa salasanan luonti -linkkiä. Anna salasana, päätä haluatko MaxMindin mainospostia ja klikkaa reset password -nappulaa. Kirjaudu sisään sähköpostiosoitteellasi ja luomallasi salasanalla.
  • Klikkaa valikosta My Licence Key. Klikkaa avautuneessa ikkunassa nappulaa Generate new licence key. Anna avaimelle haluamasi kuvaus tai tyydy oletukseen. Laita täppä ruutuun Yes ensimmäisessä kysymyksessä, jossa halutaan tietää tarvitaanko tietoja geoipupdatelle. Laita täppä ensimmäiseen valintaan eli uudemmalle versiolle. Klikkaa Confirm

 

  • Olet luonut uuden avaimen. Talleta Account/User ID sekä License key. Lisenssiavainta ei enää näytetä, joten ehkä se kannattaa varmuuden vuoksi tallentaa johonkin, vaikkakin ne saadaan talteen seuraavassa vaiheessa. Lisäksi, jos on tarve, ja vanha on kadoksissa, niin aina voi luoda uuden. Klikkaa nappulaa Download Config.

  • Sinulle ladattiin GeoIP.conf, joka pitää sisällään tarvitsemasi tietokannat (eli ne mitkä ovat sinulle sallittuja) sekä account ID:n ja license keyn.
  • Siirrä GeoIP.conf hakemistoon /etc tai luo tiedosto ja kopypeistaa sisältö:
nano /etc/GeoIP.conf

 

Tiedosto vaatii nämä tiedot:

AccountID <numeroita> 
LicenseKey <merkkejä> 
EditionIDs GeoLite2-ASN GeoLite2-City GeoLite2-Country
  • Aja SSH:ssa update: geoipupdate -v
    Vipu -v on sama kuin verbose eli kertoo mitä tapahtuu. Pääset näkemään toimiiko se vai tuleeko virheitä.
  • Tarkista cron:
nano /etc/cron.d/geoipupdate

 

Sinulta pitäisi löytyä tällainen sisältö:

  • Klikkaa Maxmindin sivuston valikosta kohtaa Download Files
  • Lataa GeoLite2 Country (.mmdb) kohdasta GZIP-tiedosto ja siirrä se FTP:llä hakemistoon /usr/share/GeoIP

  • Puretaan ladattu tar-pallo:
tar zxvf /usr/share/GeoIP/GeoLite2-Country_20210507.tar.gz
  • Siirrytään purettuun hakemistoon. Sinulla lienee hakemiston nimen päivämäärämerkintä eri:
cd GeoLite2-Country_20210507/
  • Siirretään kaikki oikeaan hakemistoon:
mv * /usr/share/GeoIP/

Kokeillaan toimiiko GeoIP tätä kautta:

mmdblookup --file /usr/share/GeoIP/GeoLite2-Country.mmdb --ip 8.8.8.8 country names en

Vastauksen pitäisi olla suunnilleen tällainen: "United States" <utf8_string>

Nyt sinulla on tehtynä neljä asiaa:

  • MaxMindin tili, jonka avulla saa tietokannan pidettyä ajantasalla
  • ohjelma, joka tekee tietokannan päivityksen cronin avulla
  • Ubuntulle ns. yleinen työkalu GeoIP-tiedon käyttöön
  • Nginxin kaipaama GeoIP-tietokanta

Nginxin asetukset

Otetaan GeoIP käyttöön Nginxillä. Tässä vaiheessa se ei tee mitään muuta kuin selvittää IP-osoitteen maan ja asettaa sen headereihin.

  • Lisää tiedoston /etc/nginx/nginx.conf alkuun ennen events-lohkoa:
load_module /etc/nginx/modules-enabled/ngx_http_geoip2_module.so;
  • Lisää http-lohkoon:
##
# GeoIP Country
##

geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
    auto_reload 5m;   # kuinka usein tarkastetaan tietokannan päiväys
    $geoip2_metadata_country_build metadata build_epoch;   # tietokannan aikaleima
    # $geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
    $geoip2_data_country_code default=FI country iso_code;
    $geoip2_data_country_name country names en;
}
  • Lisää haluamasi virtual hostin conffiin:
add_header X-Country $geoip2_data_country_name; # maan nimi englanniksi, tai 
add_header X-Country-ISO $geoip2_data_country_code;  # maan nimi ISO-lyhenteenä 

location / {
    
    ...
    
    fastcgi_param COUNTRY_CODE $geoip2_data_country_code;
    fastcgi_param COUNTRY_NAME $geoip2_data_country_name;
    
    ...
}
  • Tarkista kirotus- ja syntaksivirheet ja käynnistä Nginx uudestaan:
nginx -t
systemctl restart nginx
  • Tarkista, että maakoodi (tai maan nimi) näkyy headereissa:
curl -IL https://www.eksis.one/

Nginxin toimivuus ei vaadi maan esittämistä headereissa ja jos tyydyt Nginxin käyttöön, niin testin jälkeen voit poistaa X-Country headerin. Mutta jos välität tiedon Varnishille, niin silloin joku headeri täytyy olla.

Jos haluat maan näkyviin Nginxin logeihin, niin lisää log_format sääntöön '$geoip2_data_country_code'.  Varmista sen jälkeen, että et samalla rikkonut Fail2banin regex-sääntöjä.

Itse laitoin IP-osoitteen jälkeen maatunnuksen. Ihan siksi, että näen yhdellä silmäyksellä mihin maahan IP-osoite kohdistuu. En minä sitä oikeastaan muuhun käytä kuin varmistamiseen, että en saa odottamattomia osumia esimerkiksi komennolla

cat /var/log/nginx/access.log | grep " FI -" | grep "\" 403 "

Joku osaavampi varmasti tekisi tuon tehokkaammin, mutta se riittää minulle.

Omassa nginx.conf tiedostossa on seuraavanlainen

log_format main '$remote_addr $geoip2_data_country_code - [$time_local] '
                              '"$request_method $scheme://$host$request_uri $server_protocol" '
                              '$status $body_bytes_sent "$http_referer" '
                              '"$http_user_agent"';

Tuon ei pitäisi rikkoa Fail2bannin filttereitä, ainakaan omassa hyvinkin perustason asennuksessa.

Koska Ubuntuun asetettiin yleisempikin työkalu geo-tiedon saamiseen, niin sitäkin voi käyttää logien penkomiseen (jos osaa) ihan ilman maan viemistä logeihin. Esimerkiksi tämä komentopainajainen esittää top-25 IP-osoitteet ja niiden maat:

cat /var/log/nginx/access.log | awk '{ print $1 }' | sort | uniq -c | sort -rn | head -n 25 | awk '{ printf("%5d\t%-15s\t", $1, $2); system("geoiplookup " $2 " | cut -d \\: -f2 ") }'

Tämä taasen esittää livenä mitä mikäkin IP on juuri pyytänyt ja saanut vastaukseksi webserveriltä, ja tietysti maatiedon kanssa:

tail -f /var/log/nginx/access.log | awk '{
    "geoiplookup " $1 " | cut -d \\: -f2 " | getline geo
    printf("%-15s\t%s\t%s\t%-20s\t%s\n", $1, $6, $9, geo, $7);
  }'

Yleistettynä:

  • ensimmäiseksi asennettu Ubuntun GeoIP osaa tehdä maatunnistuksen kaikkialla, mikä liittyy IP-osoitteisiin, mutta ei Nginxin/Apachen omissa tekemisissä
  • toisena asennettu GeoIP antaa Nginxille/Apachelle mahdollisuuden tehdä taikojaan IP-osoitteen mukaisen maatiedon perusteella

Nginxin suodatukset GeoIP:n avulla

Käytännössä yleisimmät tavat hyödyntää geo-tietoa lienevät

  • määrättyjen maiden salliminen
  • määrättyjen maiden estäminen
  • kieliversioiden ohjaaminen maan mukaan (joka on kylläkin typerää, mutta muutoinhan voi toki olla maakohtaista sisältöä)

Jos estät tai sallit maiden mukaan, niin ole hieman hereillä tekemiesi suhteen. Jos kyllästyt amerikkalaisten koputuksiin, niin USA:n estäminen on sarjaa huono idea, koska samalla estät Googlen ja jos sinulla on WordPress, niin yksikään päivitys ei onnistu. Mutta koska Nginxin estolistat pätevät vain webserverille, niin vastaavaa kuin iptablesin suodatulistojen kanssa tapahtui, jossa estin Alankomaat ja whois lakkasi kertomasta tietoja eurooppalaisista IP-osoitteista, ei pääse tapahtumaan.

Maiden ISO-koodit löydät esimerkiksi GeoNames sivustolta.

Salliminen maiden mukaan

Kun sallitaan maita. tehdään whitelist, niin luetellaan kaikki ne maat, joista saa saapua. Jos ei kuulu listaan, niin ei pääse sisälle.

Se tehdään map säännöllä, esimerkiksi virtual hostin confin alkuun ennen server lohkoa, Jos haluat säännön koskevan aivan kaikkia sivustoja, niin laita tieto nginx.conf tiedostoon http lohkon alkuun. Joten per host se menisi esimerkiksi näin:

map $geoip2_data_country_code $sallitut_maat {
  default no;
  FI yes;
  AX yes;
  SE yes;
  NO yes;
}

server {
    ...
    if ($sallitut_maat = no) {
        return 403;
    }
    ... 
}

Sivustolle pääsisi silloin Suomesta. Ahvenanmaalta, Ruotsista ja Norjasta, mutta kaikista muista maista tuleville tarjoiltaisiin error 403.

Maiden estäminen Nginxissä

Estolista, blacklist, toimii tismalleen päinvastoin. Kerrotaan ehdottomasti kielletyt maat. mutta kaikki muut pääsevät läpi.

map $geoip2_data_country_code $estetyt_maat {
  default no;
  CN yes;
  IN yes;
  IQ yes;
  IR yes;
}

server {
    ...
    if ($estetyt_maat = yes) {
        return 403;
    }
    ... 
}

Sivusto antaisi error 403 Kiinalle, Intialle, Iranille ja Irakille, mutta kaikki muut pääsisivät läpi (jos estät lisäksi Vietnamin ja Venäjän, niin saat karsittua noin 80 % kaikesta haitta- ja roskaliikenteestä).

Uudelleenohjaukset maiden perusteella

Globaaleimmilla sivustoilla kävijät voidaan ohjata GeoIP:n avulla heille paremmin sopiville sivustoille. Joskus se kannattaa, joskus ei. Jos maan perusteella tekee ohjauksen, niin kannattaa miettiä jokin ratkaisu, jolla kävijä pääseekin haluamalleen maasivulle. IP-osoite kun kertoo vain siihen IP-avaruuteen rekisteröidyn maan, ei muuta, VPN on yksi, joka rikkoo moisen, mutta isojen yritysten intrat saattavat myös aiheuttaa omat temppunsa ja suomalainen käyttäjä tuleekin maailmalle yrityksen yhdysvaltalaisesta IP-osoitteesta. Tai kyseessä on siirtolainen. Tai matkoilla oleva internet-cafeen käyttäjä.

Jos IP-osoitteen maatunnistuksesta tehdään ehdoton, niin käyttäjä joutuu ikuiseen limboon, eikä se ole haluttua.

Sivusto voitaisiin lokalisoida esimerkiksi näin:

map $geoip2_data_country_code $redirect_domain {
    default no;
    FI 'fi.example.tld';
    SE 'se.example.tld';
}

server {
    server example.tld;
    ...
    if ($redirect_domain != no) {
        return 302 https://${redirect_domain}$request_uri;
    }
    ...
}

Suomalainen IP-osoite ohjaittaisiin suomalaiselle/suomenkieliselle sivustolle ja ruotsalainen vastaavasti omalleen. Kaikki muut menisivät sitten päädomainille.

Jos haluaisi vapauttaa jonkun IP-osoitteen maaohjauksesta, niin sen voisi tehdä esimerkiksi tekemällä poikkeuksen:

geo $exclude_redirect_domain {    
    default no;    
    1.2.3.4 yes;
}
map $geoip2_data_country_code:$exclude_redirect_domain $redirect_domain {    
    default no;    
    FI:no 'fi.example.tld';    
    SE:no 'se.example.tld';
}

Ylipäätään kaikki Nginxin säädöt, joissa käytetään jotain muuttujaa, toimivat geo-tiedon kanssa.

Varnish ja X-Country

Koska Nginx välittää maatiedon, niin sitä käytetään Varnishissa tismalleen samoin kuin mitä tahansa headeria. Voit estää tai ohjata, miten haluat.

Jos sinulla on vain yksi domain Varnishin takana, niin header voidaan asettaa virtual hostin confissa. Mutta jos backendejä on useampi, tai jos käytät vastaavaa rakennetta kuin minä useamman domainin kanssa, niin jokaisen olisi asetettava erikseen maatiedot headeriin. Silloin saattaisi olla helpompaa asettaa GeoIP nginx.conf tiedostossa.

Avaa /etc/nginx/nginx.conf ja laita add_header säännöt http-lohkoon GeoIP-asetusten jälkeen:

add_header X-Country $geoip2_data_country_name;
add_header X-Country-ISO $geoip2_data_country_code;

Sen jälkeen voit ohjata pyynnöt mihin haluat joko maan englantilaisen nimen tai kaksikirjaimisen ISO-koodin mukaan.

Koska Nginx asettaa maatiedon aina kun pyyntö kulkee sen mukaan, niin sitä ei pysty muuttamaan. Ainakaan minä en ole onnistunut. Toki sitä voidaan muuttaa Varnishissa ja asettaa joksikin muuksi backendin puolella, mutta se palautuu takaisin alkuperäiseen responsen myötä, kun palataan takaisin Nginxiin. Toki varsinainen magia tehdään Varnishin ja backendin välillä, mutta tuo saattaa olla huomioitava asia.

Lopullinen GeoIP2-ratkaisu

Omissa tekemisissäni on harvoin mitään lopullista. Opettelen ja samalla sitten siirrän niitä ns. tuotantoon lennossa. Ei ihan paras ratkaisu, koska olen usein laatinut serverini, saanut sivustot tarjoamaan error 5xx virheen tai sitten bannannut jokaisen saapujan. Noista oppii, mutta ehkä aidosti taloudellisesti merkityksellisillä järjestelmillä kannattaa opetella stage-serverien käyttö.

Minulla on (tätä kirjoitettaessa) hieman laajempi geo-käsittely. Laajuus tarkoittaa sitä, että minulla on suurinpiirtein kaikki mahdollinen käytössä ja ne tekevät päällekkäisiä asioita:

  • Ubuntussa on oma tapansa selvittää geo-tieto
  • UFW/iptables suodattaa ennen pääsyä serverille GeoIP:n avulla
  • Nginx sai omansa, eikä jaa tietoa kuin omiin logeihinsa
  • Varnish tekee geo-tunnistuksen VMOD:n avulla

Koska minulla ei ole maakohtaista sisältöä, niin käytän GeoIP2-tietoa vain blokkausten tarkentamiseen palomuurin jäljiltä, eikä se ole tehokas siinäkään. Suurin saavutus on oikeastaan se, että saan hassut maa/IP/GPS/yritys headerit näkyviin.

Joten aidosti minulle on eniten hyötyä iptablesin tekemästä geo-estosta, koska se vähentää tehokkaimmin serverin roskakuormaa.

Jakke Lehtonen

Teen B2B-markkinoille sisällöntuottoa sekä UX-testauksia. Samaan liittyy myös koulutukset yrityksille ja webmaailman kanssa muutoin painiville. Serverien sielunelämää on joutunut ohessa opettelmaan. Toinen puoli toiminnasta on koirien ravitsemuksen ja ruokinnan suunnittelua sekä varsinkin omistajien kouluttamista hoitamaan koiriaan oikein ja vielä paremmin. Profiili: Jakke Lehtonen