
Richard Stallman wrote the first GPL in 1989, and the thing still shapes how we build connected hardware. I’ve been designing embedded Linux devices for ten years, and if there’s one thing I’ve absorbed, it’s this: GPL compliance is not something you bolt on before shipping. It’s a design constraint. It belongs in the bill of materials, the build system, and the conversations you have with your supply chain before you’ve even settled on a processor.
This piece walks through the whole process of putting together a GPL-compliant IoT appliance—bootloader choice, kernel configuration, userspace components, how to actually hand over source code, and the hardware gotchas that catch otherwise careful teams off guard.
Understanding Which Licenses Actually Apply
An IoT device is a stack of software layers, each with its own license story. The GPL family isn’t the only one you’ll meet, but it’s by far the most demanding. GPLv2 and GPLv3 both say that if you ship a binary covered by the license, you have to provide the complete corresponding source code. LGPL components lighten the load for the rest of userspace—until you statically link against one. At that point the obligation balloons. Permissive licenses like MIT or BSD mostly ask for a credit line, but their presence next to GPL code doesn’t shrink what the GPL requires of you.
Before you write a single line of code, go map every software component. The bootloader—U-Boot, almost always—is GPLv2+. The Linux kernel is GPLv2. BusyBox, the Swiss Army knife of resource-constrained userspace, is GPLv2. If you pull in OpenSSL, stop and look at its license: it isn’t GPL-compatible. You’ll need an explicit exception or a different TLS stack like wolfSSL whenever you link against GPL code.
Bootloader and Kernel: The Foundation
This is where compliance starts, and it’s where the sloppiest mistakes live. U-Boot and Linux are both GPLv2. Both demand the exact source tree that produced the binaries you flash. Shipping a clean upstream tarball while your device actually runs a patched fork is not compliance—it’s a time bomb. The license says corresponding source. That means the precise revision, plus every board-support patch, device-tree overlay, and the exact defconfig you used.
Set up a reproducible build system on day one. Yocto Project and Buildroot are the two big names because they spit out a complete manifest: every source package, every patch, every license. I tend to reach for Yocto when a team expects to maintain the device for years. Its layer model keeps board-specific hacks cleanly separated from upstream metadata. Whichever tool you pick, the build output has to include a Software Bill of Materials (SBOM) that ties each binary to its source archive and SPDX license tag.

Userspace and the Copyleft Boundary
Userspace is where the licensing map gets messy. A typical IoT appliance runs a tiny init system, a handful of daemons for connectivity—Mosquitto for MQTT, say, which is EPL/EDL—and a custom application that actually makes your product yours. The GPL’s copyleft reach depends entirely on how these pieces talk to each other.
If your proprietary application links dynamically against glibc (LGPL) and chats with GPL daemons only through pipes or sockets, the FSF’s view is that a boundary exists. The application is a separate work. You don’t have to publish its source. But embed a GPL library into the same process address space, and the whole program needs to be GPL-licensed. When you’re not sure, keep the proprietary logic in its own binary and have it communicate with GPL services over clear, documented IPC. Write down that architecture so someone downstream can verify the separation isn’t a sham.
Designing the Physical Compliance Mechanism
Both GPLv3 and GPLv2 assume the person who owns the device can modify its software. For IoT hardware, that has teeth. You can’t lock the bootloader with fused keys that reject unsigned firmware. GPLv3 explicitly bans “Tivoization.” Even under GPLv2, the license’s spirit crumbles if the owner has no practical way to exercise the freedoms it grants.
Give people a documented reflash path. It could be a recovery-mode button sequence that boots from SD, an unlocked JTAG header with a pinout diagram, or a USB device-firmware-upgrade mode that accepts unsigned images. If you run secure-boot in production, let the user enroll their own keys. The Software Freedom Conservancy’s enforcement principles are blunt about this: withholding signing keys while shipping GPL code is a violation in spirit, and courts have agreed that technical locks can cancel the rights the license gives.
Installation Information and Scripts
GPLv3 has an “Installation Information” clause that says you must hand over any scripts, keys, or tools a person needs to install modified software on the device. Even if you ship only GPLv2 code, treat this as a baseline. Write a single script that swallows a kernel image and a rootfs and produces a flashable artifact. Test it on a reference board. Put it in the source archive. If your manufacturer uses proprietary signing tools, negotiate access or switch to a toolchain where the signing step is something your recipient can repeat.
Source-Code Distribution That Survives Audits
Compliance isn’t a one-and-done delivery. The GPL says you have to offer source to anyone who gets the binary. For an IoT device sold through retail, a written offer good for three years is legal, but a download link on the product page is cleaner and cuts support tickets. The link has to point to a complete archive—not a Git repo with forgotten submodules—and it has to stay alive for as long as you distribute the product, plus the three-year window after the final shipment.
Build the archive so a third-party developer can rebuild the firmware with one command. Bundle the toolchain binaries or a script that fetches the exact version you used. If you’re on Yocto, the tmp/deploy/sources directory holds per-package source archives. Zip those up with the build configuration and a README that lists the build host’s distro and package versions. I also throw in a checksum file for every tarball so people can check integrity.

Handling Third-Party Binaries
Wi-Fi firmware blobs, GPU microcode, cellular-modem binaries—IoT designs are full of them. The GPL doesn’t forbid shipping non-free firmware next to GPL components, as long as that firmware runs on a separate processor. But you have to label the blobs clearly and include their licenses. The linux-firmware repository is the usual starting point. Check each file’s license file, though; some blobs demand explicit redistribution permission. If a vendor hands you a binary-only library that links into a GPL userspace process, you’ve got a license conflict. Call your lawyer.
Practical Compliance Checklist
I’ve boiled the process down to a checklist that catches the most frequent disasters. Walk through it before any release candidate heads to manufacturing:
- License inventory: Every package, library, and firmware blob is listed with its SPDX identifier and a link to the full license text.
- Corresponding source archive: Built by the CI pipeline, not hand-zipped. Contains every patch, build script, and toolchain detail.
- Reproducible build: A clean checkout and a single command produce a bit-identical firmware image.
- Physical modifiability: A documented, user-accessible way to replace the firmware without vendor-only tools exists.
- Written offer: It’s in the printed manual and on the product support page, with a URL designed to outlast the product.
- Third-party compliance: All proprietary blobs sit on auxiliary processors and come with redistribution approvals.
FAQ
Do I have to open-source my entire IoT application if I use a GPL library?
Only if the GPL library and your application form a single program. If they run in separate processes and talk through documented interfaces, your application can stay proprietary. Static linking always creates a combined work, so dynamic linking or clean IPC separation is the safer road.
Can I lock the bootloader to prevent tampering and still comply with the GPL?
Under GPLv3, no. You have to provide a way to install modified software. Under GPLv2, the legal text is less explicit, but locking out user modifications guts the license’s intent. The most defensible approach: allow key enrollment so owners can sign their own firmware.
What happens if my contract manufacturer changes a GPL component without telling me?
You’re the distributor, so you’re on the hook. Audit the final firmware image before it ships. Compare the binary against your own build. If something doesn’t match, demand the modified source from the manufacturer. Write a clause into the manufacturing contract that requires notification and source delivery for any software change they make.
How long must I keep the source code available after I stop selling the device?
Three years from the date of the last distribution. If you used a written offer, you have to fulfill any valid request inside that window. A static download page is the easiest method for you and your customers.
Building a GPL-compliant IoT device is engineering, not legal guesswork. When the toolchain, the build system, and the hardware design all treat software freedom as a first-class requirement, compliance stops being a pre-launch panic and becomes a natural output of how you work. The devices we ship carry our names, and the license we pick reflects the kind of engineering community we want to keep alive.