Controlling a DJI Drone Over the Internet

In this post, I explain how I controlled a DJI Mavic Drone over the Internet to achieve a potentially unlimited range. In rescue scenarios with challenging terrains, drone operations are often limited by the controller range and signal obstructions, which can be caused by mountains or dense forests, for example. As long as there is a mobile network, the video feed and control can be provided via the Internet.
Overview
I used a DJI Mavic Drone that is usually controlled with a remote. However, there is a slider on the drone that enables direct control via an app. In that mode, the drone creates its own WiFi network. However, WiFi typically covers less than 100 meters.
To extend the range, I built a WiFi bridge using:
- A Raspberry Pi with a WLAN dongle, attached directly to the drone
- An LTE dongle to bring the Pi online (Huawei Surfstick, E3372H-320 in my case)
- A Linux server on the Internet running WireGuard as a VPN server
- An iPad with the DJI Go 4 app for control, which also connects as a WireGuard client
The idea is simple: The Raspberry Pi connects to the drone’s WiFi. Then it uses LTE to connect to the VPN server. The iPad also connects to the same VPN server. Traffic from the iPad is routed through the server to the Pi and finally to the drone using iptables (also the other way round).
Server Setup with WireGuard
On my Linux server with the public interface eth0
, I installed WireGuard, which creates a private interface wg0
. I created two client profiles for the drone and the iPad and added both to the config file /etc/wireguard/wg0.conf
. I added an extra subnet in AllowedIPs
to forward traffic to the drone’s network (192.168.2.0/24). The commands in PostUp
are automatically executed when WireGuard starts. In the config I added the following iptable rules:
iptables -A FORWARD -i eth0 -o wg0 -j ACCEPT
allows inbound packets received from the internet to be forwarded to VPN-connected clients
iptables -A FORWARD -i wg0 -j ACCEPT
allow forwarding for any traffic from the WireGuard VPN interface towards any destination
Since I wanted to allow the VPN clients (especially the iPad) to access the internet, I added the following iptable rule iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
. This Network Address Translation command replaces the source IP addresses of packets coming from the VPN clients (private addresses, like 10.66.66.1
for Pi on the drone and 10.66.66.2
for iPad) with the server’s public IP address.
I repeated the same steps for IPv6 since the LTE clients commonly get such an address from the mobile carrier:
ip6tables -A FORWARD -i wg0 -j ACCEPT
ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Similar commands can be added in PostDown
which run automatically when WireGuard stops, but with paramter -D
instead of -A
in order to purge the rules when they are not needed.
Raspberry Pi Setup
The Raspberry Pi, attached directly to the drone and powered by its micro USB port that is normally used to transfer video recordings to a computer. Therefore, no additional battery is needed.
WireGuard on the Pi
The WireGuard configuration wg0-client-drone.conf
contains the following settings:
In the [Interface]
Block, a local address is defined like 10.66.66.1
as well as a DNS server and a private key.
In PostUp
I implemented the following commands:
iptables -A FORWARD -i wlan0 -o wg0 -j ACCEPT
allows traffic from the drone’s WiFi network (reachable through wlan0
) to pass through and be forwarded into the WireGuard tunnel (wg0
)
iptables -A FORWARD -i wg0 -j ACCEPT
which allows all traffic arriving via WireGuard to be forwarded. This makes bidirectional communication possible.
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
This ensures outgoing packets leaving through the WiFi interface (wlan0
) have their original source IP replaced with the Raspberry Pi’s local WiFi IP. Without this, the drone’s WiFi network would receive packets with unknown VPN IP addresses and wouldn't route them correctly.
Again, I added similar FORWARD
rules for connecting to the server for iPv6 and added discard rules, when the Wireguard interface shuts down in PostDown
.
Of course, we also need the usual VPN Server information in the config as well in the [Peer]
section with PublicKey, PresharedKey, Endpoint (which is the public ip and port of the linux server) and the IP ranges that should be routed through the VPN, which can be set to 0.0.0.0/0,::/0
to route all IPv4 and IPv6 traffic (effectively everything).
In order to establish a connection once the Raspberry Pi starts up, we can add WireGuard to the autostart systemctl enable wg-quick@wg0
.
Connecting the Pi to the Drone’s WiFi
The Pi needs to connect to the drone’s WiFi. I used Network Manager for this. First, I ensured that the WiFi interface (wlan0
) is present with nmcli d show
To list all available WiFi networks, we can use nmcli d wifi list
. There should be a network with "Mavic" in it's SSID. We then can connect to it using nmcli d wifi connect Mavic-XXXXXX password pw_is_found_on_a_sticker_under_the_battery
.
I also added a shell script on the Pi that reconnects to the WiFi of the drone if it should lose the connection.
Conclusion and practicality of this setup
To my surprise, there is low control latency and the video signal is also transmitted in good quality. So the drone can easily be controlled using this approach.

However, cellular networks can be unpredictable and fallback strategies would be useful (currently, if a signal loss happens, the drone autonomously flies back to the last home point). Unfortunately, there are a few disadvantages, which makes the whole thing more of a proof of concept: The drone flies at a very slow speed in WLAN mode, so that long distances can hardly be covered with the limited battery life. In addition, the home point has to be reset regularly as the drone has a software border, which prevents it from moving too far away from it in WLAN mode. You could probably remove such limits with other jailbreak approaches, but I haven't looked into it.