This guide configures a Raspberry Pi 5 to be controlled directly by an iPad Pro using a single USB-C connection. It sets the Pi up as a USB Ethernet Gadget with a built-in DHCP server, so the iPad automatically gets an IP address when plugged in.
Critical Warning: The Raspberry Pi 5 requires 5V/3A to 5V/5A to run stably. A standard USB cable between the iPad and Pi usually limits power to ~4.5W (0.9A), which may cause the Pi to crash.
Use one of these two setups:
We will use Ansible to configure the kernel modules (dwc2, g_ether), install a DHCP server (dnsmasq), and manage networking.
Supported OS: Raspberry Pi OS (Bookworm), Ubuntu Server 22.04/24.04.
On your Raspberry Pi (or the machine controlling it), create a file named setup_ipad.yml:
---
- name: Configure Pi for iPad OTG with DHCP and NetworkManager
hosts: localhost
connection: local
become: yes
vars:
# The static IP for the Raspberry Pi on the USB connection
otg_ip: "10.55.0.1/24"
# The IP range assigned to the iPad
dhcp_start: "10.55.0.2"
dhcp_end: "10.55.0.6"
tasks:
# --- KERNEL CONFIGURATION ---
- name: Detect Boot Configuration Path
ansible.builtin.stat:
path: "/boot/firmware/config.txt"
register: firmware_config
- name: Set Boot Path Variable
set_fact:
boot_path: "{{ '/boot/firmware' if firmware_config.stat.exists else '/boot' }}"
- name: Enable 'dwc2' overlay in config.txt
ansible.builtin.lineinfile:
path: "{{ boot_path }}/config.txt"
regexp: '^dtoverlay=dwc2'
line: 'dtoverlay=dwc2'
state: present
notify: Reboot Pi
- name: Check for modules in cmdline.txt
ansible.builtin.shell: "grep -c 'modules-load=dwc2,g_ether' {{ boot_path }}/cmdline.txt || true"
register: cmdline_check
changed_when: false
- name: Add modules to cmdline.txt
ansible.builtin.replace:
path: "{{ boot_path }}/cmdline.txt"
regexp: '(^.*$)'
replace: '\\1 modules-load=dwc2,g_ether'
when: cmdline_check.stdout == "0"
notify: Reboot Pi
- name: Persist modules in /etc/modules
ansible.builtin.blockinfile:
path: /etc/modules
block: |
dwc2
g_ether
create: yes
# --- UBUNTU SPECIFIC NETWORKING ---
- name: Install NetworkManager (Ubuntu Only)
ansible.builtin.apt:
name: network-manager
state: present
when: ansible_distribution == 'Ubuntu'
- name: Configure Netplan to use NetworkManager (Ubuntu Only)
ansible.builtin.copy:
dest: /etc/netplan/01-network-manager-all.yaml
content: |
network:
version: 2
renderer: NetworkManager
ethernets:
all-en:
match:
name: "en*"
dhcp4: true
optional: true
when: ansible_distribution == 'Ubuntu'
notify: Apply Netplan
# --- CONNECTION SETUP ---
- name: Create Static Connection for iPad USB
community.general.nmcli:
conn_name: "ipad-usb"
ifname: "usb0"
type: "ethernet"
ip4: "{{ otg_ip }}"
state: present
autoconnect: yes
ignore_errors: yes
# --- DHCP SERVER ---
- name: Install dnsmasq
ansible.builtin.apt:
name: dnsmasq
state: present
- name: Configure dnsmasq for usb0
ansible.builtin.copy:
dest: /etc/dnsmasq.d/usb0.conf
content: |
interface=usb0
bind-interfaces
dhcp-range={{ dhcp_start }},{{ dhcp_end }},255.255.255.0,1h
# Prevent iPad from using Pi as default gateway (keeps iPad WiFi working)
dhcp-option=3
owner: root
group: root
mode: '0644'
notify: Restart dnsmasq
handlers:
- name: Apply Netplan
ansible.builtin.command: netplan apply
when: ansible_distribution == 'Ubuntu'
- name: Restart dnsmasq
ansible.builtin.service:
name: dnsmasq
state: restarted
enabled: yes
- name: Reboot Pi
ansible.builtin.reboot:
msg: "Rebooting to activate USB Gadget Mode"