VPN from Mobile IP on Raspberry Pi. WG tunnel
My knowledge of networks, routes, etc. is at the level of a housewife (as, indeed, of *nix systems), so the process of obtaining results was, to put it mildly, slow. Despite the fact that VPN in the Russian Federation seems to be in an unclear status, the technology itself is not prohibited (WG is blocked only to foreign addresses, if the server is located in the Russian Federation, then there are no problems with access to it from the Russian Federation or from abroad), so it will work, and in the case of a foreign SIM card, the IP will also be foreign with all that it implies, well, this is already a forced bonus. 🙂
Although the article is about the Raspberry Pi, its presence is unimportant, the exit point can be any other VPS, or, for example, your home router/computer, if you want to make yourself a Residential IP VPN, the point is to build a tunnel.
Setup
Paspberry Pi 5
LTE Hat (there are plenty on Alika, you can also find them on Avito, but it will also work with a simple USB modem, but I wanted a small, beautiful, solid box, from which only antennas stick out, and only power supply is suitable from cables, well, such a modem has priority (route metric) is set above WiFi by default, so no additional settings need to be made.
VPS. I’m not ready to rely on the fact that some OPSOS won’t suddenly start issuing IP as NAT, so I don’t count on DynDNS, I need a hardware version
VPS
Any server will do, I did it on FirstVDS, simply because I was already registered there and it was faster to arrange a separate server for tests, but in general it would be more correct to take a server in the country whose SIM card will be inserted into you.
So, we will assume that the server is new and the first thing we need to do is configure it. I have Ubuntu installed on my VPS, so the instructions will be for it (for Debian it seems +/- similar too)
$ adduser -m USERNAME # Создаём пользователя чтобы не работать под рутом
$ usermod -aG sudo USERNAME # Разрешаем ему выполнять команды от рута
# Коннектимся на сервер уже под НОВЫМ пользователем и обновляем систему
$ sudo apt update && sudo apt upgrade -y
Docker
Next we will install all components via Docker. I haven’t worked with it until now, but the thing turned out to be wildly convenient, especially when you do dozens of experiments/reinstallations during the setup process and the main system is practically isolated from all your crazy actions, everything that you experiment with networks will remain in the container and your server will not suddenly become unavailable due to curvature.
$ curl -sSL https://get.docker.com/ | sh # Устанавливаем Docker
$ sudo groupadd docker # Создаём группу
$ sudo usermod -a -G docker $USER # Позволяем докеру работать под текущим (созданным выше) пользователем, а не из под рута
Portainer
I chose portainer to manage docker containers. You can do it without it, everything is done on the command line, it’s faster and shorter, but it’s more convenient (and useful for further experiments)
$ sudo mkdir -p /portainer # Создаём директорию для portainer
$ sudo docker pull portainer/portainer-ce:latest # Скачиваем его последний образ
# Запускаем portainer в самом докере
# 9443 — SSL порт внутри контейнера
# 9444 — SSL порт, который будет торчать снаружи.
# Можно их делать одинаковыми, но я не очень люблю значения "по умолчанию"
$ sudo docker run -d -p 9444:9443 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /portainer:/data portainer/portainer-ce:latest
After this, you can open it in a http browserS://your.vps.server:9444, a window should appear asking you to set a user and password:
Actually, you indicate your data and then on the start page it would be useful to indicate another small detail:
Here specify the IP or server address. This is not necessary, but when you click on the port of a container, instead of going to http://0.0.0.0:PORT you will come to the right address:
Next, let's move on to managing our containers:
Wireguard (VPS)
Who is too lazy to watch how it’s done through the UI, below a way to do it all with one command
Next, you need to install Wireguard. Kind people made templates (section “Templates” in the menu on the left) for quick installation of WG “in one click”, but they are not very customizable and “in one click” did not start for me, some modification was required, so I decided that it would be better to show how to deploy a container “from scratch” , no templates.
In the upper right corner click on the blue button “Add container“, enter the container name (any), image name linuxserver/wireguard:latest
(exactly this) and add a port that will stick out. The HOST port can be anything, and the CONTAINER port must be 51820
And required UDP:
Next, scroll down the page to the section “Advanced container settings“.
In the section “Volumes“you need to specify (bind) the directory with WG configs (/config
) inside the container to some directory on our server, which we can easily get to:
Next, we need to set some environment variables on the ” tabEnv“:
# Эти два свойства мапят пользователя внутри контейнера на локального пользователя
# Того, которого мы создавали в самом начале
PUID=1000
PGID=1000
# Диапазон адресов, который будет использоваться в сети,
# которую создаст WireGuard для клиентов
INTERNAL_SUBNET=10.13.13.0
# Это просто установка таймзоны, в каждом контейнере может быть своя,
# поэтому выгодно везде ставить UTC, как мне кажется
TZ=Etc/UTC
# Ни на что не влияет, "клиентов" можно добавить позже сколько
# угодно. Можно тут даже ноль указать, это просто количество клиентов (пиров)
# для которых при старте создадутся конфигурации. Если использовать этот
# Wireguard только как VPS сервер, то можно указывать значения больше ноля
# Для нашей задачи указывать не нужно, но для проверки можно.
PEERS=2
# Если внешний порт вы поменяли, то для генерации правильных конфигов клиентам
# нужно указать этот порт и тут, если мспользовали по умолчанию, то не нужно
SERVERPORT=51888
On the “tab”Restart policy” choose “Unless stopped“so that if something happens, the container will restart, but will not restart if we stop it ourselves, manually.
Next, on the tab “Runtime & resources” need to be added necessary condition for wireguard operation: net.ipv4.conf.all.src_valid_mark=1
and also allow packets to be sent between different networksnet.ipv4.ip_forward=1
And lastly, on the “tab”Capatibilities” put the switch NET_ADMIN
to true so that WG can work with networks:
That's it, you can click on the blue button “Deploy container“, wireguard should start and your new container will appear in the list of containers.
It would be useful to check that everything is ok and click on the “logs” button to see that everything started without errors.
There, in the log, QR codes for connecting to the server will be printed. You won't need them, but you can quickly check from your phone that everything is working, for example. At this step you already have a VPN.
By the way, everything that was done above through the UI can be done with one command in the console:
docker run -d \
--name=wireguard \
--cap-add=NET_ADMIN \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Etc/UTC \
-e SERVERPORT=51888 \
-e PEERS=2 \
-e INTERNAL_SUBNET=10.13.13.0 \
-p 51888:51820/udp \
-v /portainer/wireguard/config:/config \
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--sysctl="net.ipv4.ip_forward=1" \
--restart unless-stopped \
linuxserver/wireguard:latest
Setting up a tunnel on VPS
Actually, now we need to configure the rules so that when a client and raspberry connect to this WG server, traffic from the client exits through the raspberry.
Since we mapped the internal /config directory to the real /portainer/wireguard/config, along the way /portainer/wireguard/config/wg_confs/wg0.conf
The server configuration file will be generated:
$ nano /portainer/wireguard/config/wg_confs/wg0.conf
[Interface]
Address = 10.13.13.1
ListenPort = 51820
PrivateKey = VPS_PRIVATE_KEY
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth+ -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth+ -j MASQUERADE
[Peer]
PublicKey = CLIENT_PUBLIC_KEY
PresharedKey = CLIENT_PSK
AllowedIPs = 10.13.13.2/32
[Peer]
PublicKey = PI_PUBLIC_KEY
PresharedKey = PI_PSK
AllowedIPs = 10.13.13.3/32
If the task was “start your VPN server,” then we could finish here, but we need to tweak it slightly:
# Удаляем сгенерённый файл
$ rm /portainer/wireguard/config/wg_confs/wg0.conf
# Создаём новый
$ nano /portainer/wireguard/config/wg_confs/wg0.conf
[Interface]
# Адрес нашего "сервера"
Address = 10.13.13.1/32
# Порт внутри контейнера для коннекта (не внешний, торчащий наружу)
ListenPort = 51820
# Приватный ключ сервера
PrivateKey = VPS_PRIVATE_KEY
# Если вам для каких-то задач требуется доступ к вашему VPS "изнутри"
# Например, какие-то порты из интернета вы сделали недоступными,
# то можно раскомментировать эту строчку
# PostUp = iptables -t nat -A PREROUTING -d 10.13.13.1/32 -j DNAT --to-destination 172.17.0.1
# Либо использовать более "общий" вариант, в котором конкретные адреса
# подставятся автоматически, обе команды делают одно и то же:
# PostUp = iptables -t nat -A PREROUTING -d $(ip addr show %i | awk '/inet/ {print $2}') -j DNAT --to-destination $(ip addr show eth0 | awk '/inet/ {print $2}' | awk -F"." '{print $1"."$2"."$3".1"}')
# В командах ниже %i будет заменён на имя сетевого интерфейса wireguard
# По умолчанию это 'wg0'
# Так как WG находится в контейнере, то нам не нужны тут никакие
# дополнительные таблицы маршрутизации, чтобы разделять трафик
# на WG/не-WG: ещё один плюс контейнеров докера.
# Так же, мы не выходим в интернет через этот сервер, маршрутизация
# в интернет (как в автосгенерёном конфиге выше) нам тоже не нужна
# Настройка пира нашей Raspberry Pi
[Peer]
# ПУБЛИЧНЫЙ ключ клиента
PublicKey = PUBLIC_PI_KEY
# Так как через данный пир мы будем ходить в интернеты, то нельзя ограничивать
# тут адреса, нули означают "разрешены любые коннекшены".
# Зарезервируем ему адрес "10.13.13.2/32", просто держим в голове
AllowedIPs = 0.0.0.0/0
# Наш ноутбук, телефон, роутер, что угодно, что хочет в интернет
# через VPN, и желает, чтобы снаружи его IP светился как "мобильный"
[Peer]
PublicKey = PUBLIC_CLIENT_1_KEY
AllowedIPs = 10.13.13.3/32
# Второй и последующие клиенты, если нужно подключить больше одного девайса
[Peer]
PublicKey = PUBLIC_CLIENT_2_KEY
AllowedIPs = 10.13.13.4/32
Save (Ctrl+O), exit (Ctrl+X).
I removed PresharedKey (this is additional protection for the strength of the peer key).
# Перезапускаем контейнер с WG
$ docker restart wireguard
To generate keys you can use: online generatorsas well as a console command for wireguard, but since wg is most likely not installed anywhere other than containers, the command can only be executed inside the container. On Raspberry or on VPS, or on any other computer where wg is installed – it doesn’t matter. In our case, the following can be done on any of the peers:
# Запустить шелл в контейнере с именем "wireguard"
$ docker exec -it wireguard sh
# Сгенерировать пару публичный-приватный ключ (можно нагенерить с десяток,
# сразу на все пиры):
$ priv=`wg genkey` && printf "Private key: $priv\nPublic key: `echo "$priv" | wg pubkey`\n" && unset -v priv
# Пример вывода:
# Private key: EIrYKTpC93LiFBFsoyH/v8eCmMfD4rJLSmc2cgDl9lc=
# Public key: I1mrtQTkguQRbD5bNTPGk8Li3EbBhcDmc2xCNaTIwj0=
# Выход из шелла контейнера обратно в хост:
$ exit
Raspberry Pi
This is probably the easiest way: put the parts together, insert the SIM card, install Raspberry Pi OS, that’s it according to manuals from offsiteit is impossible to make a mistake there. We select Pi Lite x64 as host OS. I conducted quite a lot of different experiments and tested a couple of different Hats for raspberry; on other OSes like ubuntu they were not always detected without a tambourine, and the minimum official axis supports them out of the box, and we don’t need a UI on the server.
When installing the official OS, you can specify a user (he will no longer be root, which is what we need), set a password for him, and also specify the home network parameters so that when the raspberry starts, it will automatically connect to it. Next, on your router you can find out its IP in order to connect. So you don’t need to connect any monitors or keyboards to this box; you can put it on the power bank next to you and continue setting it up.
As in the case of Docker, until now I have not touched single-board computers, now I have several of them and have a desire to do something interesting on them, a server that consumes 5W is great.
Docker+Portainer
The only difference from VPS is that now your server is next to you, you can even put it in your pocket, so the steps are almost identical. You can act exactly as described above in the VPS section, or you can turn to helper scripts from pi-hosted (a good set of scripts for those who want to turn their Raspberry into a monster).
Wireguard (Pi)
In order not to post a bunch of screenshots again, I will leave only the console command that launches the container with WG (in this example I chose port 51999, it is not necessary to leave it always and everywhere as the default 51820):
docker run -d \
--name=wireguard \
--cap-add=NET_ADMIN \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Etc/UTC \
-e INTERNAL_SUBNET=10.13.13.0 \
-p 51999:51820/udp \
-v /portainer/Files/AppData/Config/wireguard/config:/config \
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--sysctl="net.ipv4.ip_forward=1" \
--restart unless-stopped \
linuxserver/wireguard:latest
In fact, you can copy the previous (from the VPS section) command. With WG there is no difference between “server” and “client”, everything is a “peer”.
The only difference here is the absence PEERS
in order to show that it is optional and you can add as many clients as you like, as well as a different path to the configuration directory, since I used pi-hosted, and this is the default path there.
Setting up a tunnel on Raspberry Pi
# Удаляем сгенерённый файл
$ rm /portainer/Files/AppData/Config/wireguard/config/wg_confs/wg0.conf
# Создаём новый
$ nano /portainer/Files/AppData/Config/wireguard/config/wg_confs/wg0.conf
[Interface]
PrivateKey = PI_PRIVATE_KEY
Address = 10.13.13.2/32
# Если хочется использовать RPi как VPS "сервер" напрямую, то
# можно тут указать порт, а ниже добавить клиента
ListenPort = 51820
# Добавляем некие правила при старте WG
# Все входящие пакеты в сеть WG (wg0 интерфейс) помечаются меткой 0x30
# Метка может быть любая, если бы мы не запускались в контейнере, то нужно
# было бы следить, чтобы данную метку не ставил кто-то ещё и выбирать уникальную
PreUp = iptables -t mangle -A PREROUTING -i %i -j MARK --set-mark 0x30
# Подменяем всем исходящим, помеченным меткой 0x30 пакетам адрес на
# адрес согласно текущим таблицам маршрутизации.
# Иными словами, если у нас кто-то из VPN сети просится в интернет, то
# позволяем этому пакету выйти через любой интерфейс, под который он попадает
# не заставляя его принудительно ходить только через LTE/WiFi/LAN
PreUp = iptables -t nat -A POSTROUTING ! -o %i -m mark --mark 0x30 -j MASQUERADE
# Отменяем два предыдущих правила при остановке WG
PostDown = iptables -t mangle -D PREROUTING -i %i -j MARK --set-mark 0x30; iptables -t nat -D POSTROUTING ! -o %i -m mark --mark 0x30 -j MASQUERADE
# Тут указываем параметры коннекшена к нашему VPS
[Peer]
PublicKey = VPS_PRIVATE_KEY
# Нужно указать public IP/host нашего VPS и тот порт,
# который мы там замапили
Endpoint = vps.host.ip:51888
# Разрешаем трафик из всей wg подсети,
# всех пиров от 10.13.13.1 до 10.13.13.255
AllowedIPs = 10.13.13.0/24
# Каждые 15 секунд посылать хэртбиты, дабы в случае,
# если мы за NAT, то не отвалиться
PersistentKeepalive = 15
# Если хочется использовать и этот WG как "сервер",
# то можно добавить "клиентов" и тут, но для коннекта вам потребуется
# знать реальный IP этой малинки (например, вы с ней в одной локалке/WiFi
# или ОПСоС выделил нормальный, доступный IP
[Peer]
PublicKey = DIRECT_CLIENT_PUBLIC_KEY
# Так как все пиры в итоге объединятся в одну сеть, то нужно следить
# чтобы адреса не пересекались и так как в конфиге VPS мы остановились
# на клиенте с адресом 10.13.13.4, то здесь минимальный будет уже 5
# Они не обязательно должны идти по порядку, если что
AllowedIPs = 10.13.13.5/32
Save (Ctrl+O), exit (Ctrl+X).
# Перезапускаем контейнер с WG
$ docker restart wireguard
Clients
That's it, the tunnel is configured and working, all that remains is to create configs for clients and transfer them, in fact, to the clients themselves (mobile phone, laptop).
We had 2 clients on the VPS, here is an example of their configurations:
Client 1 on VPS (laptop/router)
[Interface]
# ПРИВАТНЫЙ ключ нашего клиента
PrivateKey = PRIVATE_CLIENT_1_KEY
# Этот адрес должен соответстовать адресу, который был указан
# в конфиге на VPS
Address = 10.13.13.3/32
# DNS сервер для всех запросов, без его указания доступ
# в инернет у вас будет работать только при указании прямых
# IP адресов. Я использую гугл (8.8.8.8) или Cloudflare (1.1.1.1)
DNS = 1.1.1.1
# VPS
[Peer]
# ПУБЛИЧНЫЙ ключ VPS сервера
PublicKey = PUBLIC_VPS_KEY
# Так как мы собираемся выходить в интернеты через эту точку
# то назад нам могут прийти пакеты с абсолютно любых IP
# поэтоуму нам не нужно ограничивать тут "разрешённые" адреса
# ставим "разрешать вообще всё"
AllowedIPs = 0.0.0.0/0
# Публичный IP сервера и порт, который мы ему задавали
Endpoint = vps.host.ip:51888
Client 2 on VPS (smartphone)
Exactly the same config, only the private key is needed from the second client and the address will be 10.13.13.4/32
Client 3 on Raspberry Pi (direct connection, no VPS)
Again, everything is practically the same:
[Interface]
PrivateKey = PRIVATE_CLIENT_3_KEY
# DNS может быть у каждого клиента свой
DNS = 8.8.8.8
# Внимание на адрес
Address = 10.13.13.4/32
[Peer]
# Здесь уже данные от Raspberry Pi, не от VPS
PublicKey = PUBLIC_PI_KEY
AllowedIPs = 0.0.0.0/0
# Адрес Raspberry Pi
# (локальный, если вы в одной локалке, либо публичный ОПСоСа)
# Порт не от VPS, а тот, который экспортировали в контейнере на RPi
# В нашем примере это был 51999
Endpoint = local.or.good.public.raspberry.ip:51999
Actually, that's all. The tunnel is configured, the IP is now human, and if you use a foreign SIM card (even in roaming), you also get a foreign IP with all the bonuses. You can look for some friend who will share five watts of electricity at home; you don’t need to ask him for the Internet.
Examination also says that we seem to be ok:
When the servers are restarted, the containers rise and connect automatically; if the Raspberry or VPS crashes, the clients’ Internet falls off by default, so it’s impossible to accidentally expose your real IP.
An elevated tunnel does not in any way affect the traffic of the VPS or Raspberry itself, since it is located in a container and the server itself goes directly to the Internet, you can check this with the command curl 2ip.io
to find out your external IP in the VPS or Raspberry console
You can check the status of the interface, connected clients and the amount of traffic passed through them with the command wg
inside the container:
# Запустить шелл в контейнере с именем "wireguard"
$ docker exec -it wireguard sh
# Выводим состояние Wireguard
$ wg
Conclusion
Usually LTE download speeds are much lower than download speeds, but I came across some kind of wrong SIM card in tests, in which download and upload speeds are equal, however, it is logical to assume that when working through the “download” tunnel it will be what you send it, and “download” what you want to download from the Internet, so you will have a speed limit based on the minimum parameter (usually the LTE upload speed)
“Today I understood a lot” (c)
I still have quite a lot of plans for this Raspberry itself; this was the first step in a rather long and difficult journey of understanding these “network technologies” of yours. In thoughts of increasing fault tolerance (balancing Internet connections, so that if at the place where the raspberry is installed, in addition to a 220-volt outlet, there is access to WiFi and/or wire when LTE is disabled, access to the box remains), it is possible to add some other tunnels, and sooner In total there will be a container with a smartphone emulator and FakeGPS. So far, all these topics are unknown to me, but there is a desire and need to study them.
Useful links
Unofficial, but very informative Wireguard documentation.
Good article about different types of tunnels on Wireguard (And one more there too).