How to Set Up Geo-IP Country Based Stream Viewing
IP to Geolocation
IP-to-geolocation allows you to estimate where a user connecting to your server is located. For precise results, you’ll need a paid database or service specializing in geolocation. Free options, such as MaxMind's GeoLite2, offer reasonable accuracy for identifying countries but may lack precision for city-level details. MaxMind's tools are widely available and easy to use, making them a great starting point for Geo-IP functionality.
Requirements
- Linux (Ubuntu 24.04 is used in this guide)
- Basic Bash knowledge
Steps in this guide
- Install
geoiplookup
- Set up the script for
USER_NEW
- Configure the
USER_NEW
trigger in MistServer - Test and troubleshoot the script
1. Install geoiplookup
We’ll use the free GeoLite2 database from MaxMind, available through most Linux package managers. Keep in mind that the free version has limited accuracy. Should better precision be required you might want to look into the MaxMind developer documentation and integrate with their available services.
Installation on Ubuntu 24.04
Run the following command to install GeoIP tools:
apt install geoip-bin geoip-database
This installs the country-based GeoIP database and provides the geoiplookup
tool. You can use this tool to identify the location of an IP address:
geoiplookup ADDRESS
With geoiplookup
installed, you’re ready to set up your script.
2. Set up the script for USER_NEW
We’ll create two script versions:
geoipAllow: Allow viewers from specified countries. geoipDeny: Deny viewers from specified countries.
You can choose one depending on your needs. Don’t activate both scripts on the same stream, as this could create conflicting behavior.
Both scripts use ISO 3166-1 Alpha-2
country codes for identification. Update the country codes and logging settings as needed.
- GeoIPAllow
- GeoIPDeny
geoIPAllow
The geoIPAllow script allows viewers from specific countries and denies all others.
#!/bin/sh
#This trigger is meant to work with minimum bash. Dependencies are:
# cat , date, geoiplookup
# Usage: Any countries in the CLIST will be checked and if the viewer is from a country in the list playback is ALLOWED.
#Countries to match against matching list as ISO_3166-1_alpha-2 for example: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
# Countries should be space separated and between ", example: CLIST=("NL" "US" "DE" )
CLIST=( )
#Acceslog will keep track of useful reject/accept messages. Feel free to uncomment the lines with $ACCESSLOG in them to remove spam
LOGGING=true
ACCESSLOG=/path/to/accesslog
#Collect the trigger payload
DATA=`cat`
NOW=`date`
#Stream name attempted from 1st line
STREAM=`echo "$DATA" | sed -n 1p`
#IP address requester logged from 2nd line
IP=`echo -n "$DATA" | sed -n 2p`
#Master address is allowed to view everything and skips the check.
MASTER="127.0.0.1"
if [ "$IP" = "$MASTER" ];then
echo -n true
if [ $LOGGING = true ] ; then
echo "$NOW - $IP has all access, allowing for $STREAM" >> $ACCESSLOG
fi
exit 0
fi
#Add any view attempt to accesslog
if [ $LOGGING = true ] ; then
echo "$NOW - checking $IP $STREAM " >> $ACCESSLOG
fi
COUNTRYFULL=`geoiplookup $IP`
COUNTRYSHORT=`echo ${COUNTRYFULL#*:}`
# Check if "IP Address not found" is the result & exit by checking for the word Address, potentially a problem if a Country ever decides that the word "Address" should be in their name.
if [[ $COUNTRYSHORT =~ 'Address' ]]; then
echo -n false
if [ $LOGGING = true ]; then
echo "Viewer from $IP for $STREAM address not found, rejecting" >> $ACCESSLOG
fi
exit 0
fi
COUNTRYCODE=`echo ${COUNTRYSHORT:0:2}`
#Full debugging information, only uncomment if you want full visibility on what is happening.
#echo "$DATA" >> $ACCESSLOG
if [[ ${CLIST[@]} =~ $COUNTRYCODE ]]; then
echo -n true
if [ $LOGGING = true ] ; then
echo "Viewer from $IP for $STREAM is from White-listed $COUNTRYCODE, allowing playback" >> $ACCESSLOG
fi
else
echo -n false
if [ $LOGGING = true ] ; then
echo "VIEWER from $IP for $STREAM is from $COUNTRYCODE, rejecting" >> $ACCESSLOG
fi
fi
Save the script to a memorable location and make it executable.
Don't forget to:
- Fill in the country codes
- Fill in logfile location or set off logging
- Make the script executable through
chmod +x
- Optionally set the master IP to always allow yourself in
geoIPDeny
The geoIPDeny script denies viewers from specific and unknown countries and allows all others.
#!/bin/sh
#This trigger is meant to work with minimum bash. Dependencies are:
# cat , date, geoiplookup
# Usage: Any countries in the CLIST will be checked and if the viewer is from a country in the list playback is DENIED.
#Countries to match against matching list as ISO_3166-1_alpha-2 for example: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
# Countries should be space separated and between ", example: CLIST=("NL" "US" "DE" )
CLIST=( )
#Acceslog will keep track of useful reject/accept messages. Feel free to uncomment the lines with $ACCESSLOG in them to remove spam
LOGGING=true
ACCESSLOG=/path/to/accesslog
#Collect the trigger payload
DATA=`cat`
NOW=`date`
#Stream name attempted from 1st line
STREAM=`echo "$DATA" | sed -n 1p`
#IP address requester logged from 2nd line
IP=`echo -n "$DATA" | sed -n 2p`
#Master address is allowed to view everything and skips the check.
MASTER="127.0.0.1"
if [ "$IP" = "$MASTER" ];then
echo -n true
if [ $LOGGING = true ] ; then
echo "$NOW - $IP has all access, allowing for $STREAM" >> $ACCESSLOG
fi
exit 0
fi
#Add any view attempt to accesslog
if [ $LOGGING = true ] ; then
echo "$NOW - checking $IP $STREAM " >> $ACCESSLOG
fi
COUNTRYFULL=`geoiplookup $IP`
COUNTRYSHORT=`echo ${COUNTRYFULL#*:}`
# Check if "IP Address not found" is the result & exit by checking for the word Address, potentially a problem if a Country ever decides that the word "Address" should be in their name.
if [[ $COUNTRYSHORT =~ 'Address' ]]; then
echo -n false
if [ $LOGGING = true ]; then
echo "Viewer from $IP for $STREAM address not found, rejecting" >> $ACCESSLOG
fi
exit 0
fi
COUNTRYCODE=`echo ${COUNTRYSHORT:0:2}`
#Full debugging information, only uncomment if you want full visibility on what is happening.
#echo "$DATA" >> $ACCESSLOG
if [[ ${CLIST[@]} =~ $COUNTRYCODE ]]; then
echo -n false
if [ $LOGGING = true ] ; then
echo "Viewer from $IP for $STREAM is from blocked $COUNTRYCODE, rejecting" >> $ACCESSLOG
fi
else
echo -n true
if [ $LOGGING = true ] ; then
echo "VIEWER from $IP for $STREAM is from $COUNTRYCODE, allowing playback" >> $ACCESSLOG
fi
fi
Save the script to a memorable location and make it executable.
Don't forget to:
- Fill in the country codes
- Fill in logfile location or set off logging
- Make the script executable through
chmod +x
- Optionally set the master IP to always allow yourself in
3. Configure the USER_NEW
trigger in MistServer
Once your scripts are ready, integrate them with MistServer using the USER_NEW
trigger:
- Navigate to the Triggers page in MistServer.
- Create a new trigger and select
USER_NEW
. - Fill in the fields as shown below:
Applies to: Select specific streams for the script. If left blank, the script applies to all streams.
Handler: Provide the path to your script.
For example: /path/to/script/geoIPAllow
or geoIPAllow
if available in path.
Blocking: Yes Blocking should be set for the script to work.
Default response: false The default response is what happens should the script fail, you will want this to false in order to block any unchecked viewers.
4. Test and troubleshoot the script
To test or troubleshoot the script, simulate a USER_NEW trigger by passing a stream name
and address
manually.
You can do so by using echo
:
echo -e "anything\nADDRESS" | /path/to/geoIPAllow
The value stream name
is not actually checked, it is only passed to the script as it's a required field for the trigger to work. Whether a stream is checked is determined by which streams are ticked in the applies to
field of the USER_NEW
trigger.
Make sure to keep the newline \n
in there or it will not work!
Example:
echo -e "anything\n149.210.147.206" | geoIPAllow
You’ll see a true or false response in the terminal, indicating whether the viewer is allowed. If logging is enabled, check the log for detailed information:
Common issues
Script is not responding
Most likely you forgot to make the script executable. Please do so with: chmod +x
Script is giving errors about a file not existing
You've forgotten to set the accesslog. Please do so or turn off logging by setting LOGGING to false.
geoiplookup gives an error
Most likely you do not have geoiplookup
installed. Please verify if it's in the package you have installed previously