How to skip ChatGPT from WireGuard or OpenVPN on Linux

ChatGPT (short for Chat Generative Pre-trained Transformer) is a chatbot by OpenAI. It provides answers to your queries using learning techniques based on AI/ML. Unfortunately, ChatGPT deny access when connected via VPN (Virtual Private Network) such as WireGuard or OpenVPN, and you will be blocked with the following message:
How to skip ChatGPT from WireGuard or OpenVPN on Linux
Let us see how to skip the ChatGPT domain from WireGuard or OpenVPN access while you can access corporate resources behind VPN.

Procedure to skip ChatGPT from WireGuard or OpenVPN on Linux

The logic is straightforward. Find the chat.openai.com IP address and set the routing policy to skip the VPN interface. By default, WireGuard or OpenVPN will route all traffic via the VPN interface but will set metrics lower than WireGuard or OpenVPN interface and directly route via our router. My setup is as follows:

  • Debian or Ubuntu Linux desktop
  • WireGuard or OpenVPN located at Linode or AWS
  • Default router IPv4: 192.168.2.254

Step 1 – Find your default routing info

Once connected to WireGuard/OpenVPN, use the ip command to list the routing table:
$ ip route show
Here is what I see:

default via 192.168.2.254 dev enp0s31f6 proto dhcp metric 100 
10.83.200.0/24 dev lxdbr0 proto kernel scope link src 10.83.200.1 
169.254.0.0/16 dev ln-sg scope link metric 1000 
172.16.0.0/24 dev ln-sg proto kernel scope link src 172.16.0.6 metric 50 
192.168.2.0/24 dev enp0s31f6 proto kernel scope link src 192.168.2.25 metric 100 

My WireGuard interface named ‘ln-sg’ take priority using metric 50 over the default metric 100. So the trick is to add the chat.openai.com IP address with a lower metric and directly pass it via 192.168.2.254 default gateway IP address.

An explanation of the Automatic Metric feature for IPv4 routes

Router metrics are configuration values to make routing decisions. Router metrics help the router choose the best route among multiple feasible routes to a destination. The route will go in the direction of the gateway with the lowest metric. A router metric is typically based on information such as path length, bandwidth, load, hop count, path cost, delay, maximum transmission unit (MTU), reliability and communications cost.

Table 1: The following table outlines the criteria that is used by
my Linux desktop to assign metrics for routes
Link/Dest/Route Metric
chat.openai.com (or any other IP/domain of your choice) 10
WireGuard/OpenVPN 50
Default 100

Step 2 – Finding out the chat.openai.com IP address

Use the dig command or host command:
$ d='chat.openai.com'
$ dig +short A "$d" | grep -v '\.$'
$ ips="$(dig +short A "$d" | grep -v '\.$')"
$ echo "$ips"

Step 3 – Adding the chat.openai.com IP address to routing table

Let us set some shell variable:
$ my_gw="192.168.2.254" #Default GW
$ metric="10" #Routing metric value

Let us use bash for loop to add those IPs:

for i in $ips
do 
  sudo ip route add "$i" via "$my_gw" metric "$metric"
done

Want to list newly added IP address? Use the ip command:
$ ip route show
$ ip route show | grep -w 'metric 10'

Here is what I see:

104.18.2.161 via 192.168.2.254 dev enp0s31f6 metric 10 
104.18.3.161 via 192.168.2.254 dev enp0s31f6 metric 10 

Step 4 – Test it

Fire the web browser and test it by visiting https://chat.openai.com/ URL:

Connected to the ChatGPT

Click to enlarge

Step 5 – Deleting the chat.openai.com IP address from the routing table

Again use the ip command as follows:
$ for i in $ips; do sudo ip route del "$i"; done

Step 6 – Creating a shell script for automation

The chat.openai.com will change its IP address from time to time. So here is a generic script that adds, removes, and lists chat.openai.com and a few other domains that refused to work when connected to VPN.

routing.policy shell script

#!/bin/bash
# routing.policy - Main script to add, remove and list routing policy
# Author : Vivek Gite {www.cyberciti.biz} under GPLv 2.x+
# ----------------------------------------------------------------------
set -e
 
# Set metric and gateway as per your needs 
metric="10" 
my_gw="192.168.2.254"
domain="chat.openai.com facebook.com fbcdn.net static.xx.fbcdn.net www.facebook.com"
ips=""
me="${0##*/}" # who am I?
 
get_domain_ip_lists(){
    for d in $domain
    do
        ips="${ips} $(dig +short A "$d" | grep -v '\.$')"
    done
    ips="${ips/$'\n'/ }" # remove '\n'
    ips="$(tr ' ' '\n'<<<"${ips}" | sort -u | xargs)" # remove duplicate ips
}
 
is_route_exists(){
    local i="$1"
    out="$(ip route show "$i")"
    if [[ "$out" != "" ]] 
    then
        return 0  # True
    else
        return 1 # False
    fi
 
}
add_opneapi_route(){
    check_for_root_user
    echo "Adding ${ips/$'\n'/,} to routing table ..." 1>&2
    for i in $ips
    do
        if ! is_route_exists "$i"
        then
            sudo ip route add "$i" via "$my_gw" metric "$metric"
        else
            echo "$me route for $i already exists, skiping ..."
        fi
    done
}
 
remove_opneapi_route(){
    check_for_root_user
    echo "Removing ${ips/$'\n'/,} from routing table ..." 1>&2
    for i in $ips
    do
        if is_route_exists "$i"
        then
            sudo ip route del "$i" via "$my_gw"
        else
            echo "$me route for $i not found, skiping ..."
        fi
    done
}
show_openapi_route_status(){
    echo "Routing info for the '$domain' (${ips/$'\n'/,}) ..." # remove newline from the ${ips}
    for i  in $ips
    do
        ip route show "$i"
    done
 
}
 
check_for_root_user(){
if [[ $EUID -ne 0 ]]; then
   echo "$me script must be run as root" 1>&2
   exit 1
fi
}
 
## main ##
get_domain_ip_lists # set '$ips' 
case "$me" in
    routing.policy.add) add_opneapi_route;;
    routing.policy.delete) remove_opneapi_route;;
    routing.policy.remove) remove_opneapi_route;;
    routing.policy.show) remove_opneapi_route;;
    routing.policy.status) show_openapi_route_status;;
    *) echo "Usage: routing.policy.add|routing.policy.delete|routing.policy.status";;
esac

nixcbz[failed to get contents] - contact @ [email protected] with the url

First, set up execution permission using the chmod command $ chmod +x -v routing.policy
mode of 'routing.policy' changed from 0664 (rw-rw-r--) to 0775 (rwxrwxr-x)

Now set those links:
$ ln -sv routing.policy routing.policy.add
$ ln -sv routing.policy routing.policy.remove
$ ln -sv routing.policy routing.policy.delete
$ ln -sv routing.policy routing.policy.show
$ ln -sv routing.policy routing.policy.status

Verify it using the ls command:
$ ls -l routing.policy*
Outputs:

-rwxrwxr-x 1 vivek vivek 1913 Feb  3 00:07 routing.policy
lrwxrwxrwx 1 vivek vivek   14 Feb  3 00:08 routing.policy.add -> routing.policy
lrwxrwxrwx 1 vivek vivek   14 Feb  3 00:08 routing.policy.delete -> routing.policy
lrwxrwxrwx 1 vivek vivek   14 Feb  3 00:08 routing.policy.remove -> routing.policy
lrwxrwxrwx 1 vivek vivek   14 Feb  3 00:08 routing.policy.show -> routing.policy
lrwxrwxrwx 1 vivek vivek   14 Feb  3 00:08 routing.policy.status -> routing.policy

Test it:
$ sudo ./routing.policy.add
$ sudo ./routing.policy.status
$ traceroute chat.openai.com #<--test routing
$ sudo ./routing.policy.delete

Summing up

I tested this on my Debian and Ubuntu Linux desktop with WireGuard and OpenVPN. It worked like a charm and should work with any other Linux distro as long as ip command works. In short, we can skip specific IP addresses from being routed through a VPN connection on Linux (or any other operating system such as macOS or BSD) as long as you can add routing rules to the system’s routing table.

About the author: Vivek Gite is Editor-in-Chief and the man behind nixCraft and OpensourceFlare ✨. He creates and maintains content on both sites as accurately as possible. Since 2000 Vivek has written over 7k+ posts that have been read many times. He is a die-hard fan of FLOSS and a full-time Linux desktop user since 1996. OpensourceFlare provides in-depth guides about Linux, BSD, programming, and other IT topics for Patreon subscribers without any ads or tracking. Get the latest tutorials on Linux, Open Source & DevOps via RSS feed or weekly email newsletter.

0 comments… add one

Leave a Reply

Your email address will not be published. Required fields are marked *

Use HTML <pre>...</pre> for code samples. All comments must be on the topic, and offtopic comments will be automatically removed.