Modern Kannel: A No-WAP, Systemd-Ready SMS Gateway
Disclaimer: I have no relation to the Kannel development team or the official Kannel project. This is an independent hobby project based on a Kannel SVN snapshot.
💾 Source Code
📦 GitHub Repository: github.com/vaska94/kannel
Forked from SVN snapshot. Cleaned, modernized, and ready for Rocky Linux 10.
If you’ve worked with SMS gateways in the past decade, you’ve likely encountered Kannel. For those unfamiliar, Kannel is an open-source gateway that allows you to send and receive SMS messages via HTTP, SMPP, or other protocols — typically used by telcos, banks, and bulk SMS providers. Originally designed as both a WAP (Wireless Application Protocol) gateway and SMS gateway, Kannel has been a workhorse of mobile messaging infrastructure since the early 2000s. But times have changed, and WAP has gone the way of the dodo. It was time for Kannel to evolve.
The Problem: Legacy Bloat
Kannel’s codebase had accumulated significant technical debt over its 20+ year history. The project still carried extensive WAP functionality that nobody uses anymore - entire directories dedicated to WML scripts, WBMP image handling, and WAP push services. This legacy code wasn’t just dead weight; it was actively hampering modern deployments:
- Build complexity with unnecessary dependencies
- Security surface area from unmaintained WAP components
- Confusing configuration options mixing SMS and WAP functionality
- OpenSSL compatibility issues with deprecated certificates
- Outdated initialization systems (init.d scripts from the early 2000s)
The stable Kannel 1.4.5 release simply won’t build on modern distributions like Rocky Linux 10 due to library incompatibilities. Even after fixing the build issues, Kannel 1.4.5 kept crashing when using Redis for DLR storage — which was the tipping point that led to this project. I switched to an SVN snapshot version because it contains many fixes, especially for Redis DLR storage support. The only distro still providing Kannel packages is Debian 12, built with ancient libraries. As a Rocky Linux shop, I wasn’t thrilled about running several Debian servers just for SMS gateway functionality.
The Solution: Radical Simplification
Working with Claude AI, I embarked on a modernization journey that would strip Kannel down to its essential purpose: being an excellent SMS gateway. Development was done on Arch Linux (bleeding edge is perfect for catching compatibility issues early), with production deployment targeted at Rocky Linux 10 - a solid enterprise choice for SMS infrastructure. Here’s what I accomplished:
1. Complete WAP Removal
I performed surgical removal of all WAP-related functionality:
# Removed directories:
- wap/ # WAP gateway implementation
- wmlscript/ # WML script engine
- radius/ # RADIUS authentication
- soap/ # Legacy SOAP/ParlayX support
- debian/ # Outdated packaging
- solaris/ # Solaris-specific files (RIP Solaris)
# Removed files:
- bb_udp.c # WDP/UDP bearer functionality
- seewbmp # WBMP image viewer
- pixmapgen.pl # WBMP converter
This wasn’t just a rm -rf
operation. I carefully traced through the codebase, removing --disable-wap
configure flags, NO_WAP
preprocessor blocks, and cleaning up the build system to work without these components.
2. Modern SSL/TLS Support
The old SSL certificates were using 1024-bit RSA with MD5 signatures - completely unacceptable for modern OpenSSL 3.5.0 (especially on Rocky Linux 10 with its strict crypto policies). I replaced them with proper 2048-bit RSA certificates using SHA256:
# Added convenient make targets:
make ssl-certs # Generate new certificates
make ssl-certs-clean # Clean up certificate files
3. Systemd Integration
Perhaps the most impactful modernization was adding proper systemd service files. No more ancient init.d scripts, or running services as root! The new services include:
- Security hardening:
NoNewPrivileges
,ProtectSystem
,ProtectHome
- Proper dependencies: smsbox waits for bearerbox
- Resource limits: Controlled file descriptor limits
- Monitoring integration: Status script that queries the HTTP admin interface
Here’s a snippet from the bearerbox service file:
[Service]
Type=simple
User=kannel
Group=kannel
ExecStart=/usr/local/sbin/bearerbox -v 0 /etc/kannel/kannel.conf
Restart=on-failure
RestartSec=10
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log/kannel /var/spool/kannel
4. Test Infrastructure Fixes
The test suite was broken due to:
- Hanging processes from missing cleanup handlers
- Hardcoded relative paths
- SSL PANIC errors from the outdated certificates
I fixed all of these issues, ensuring tests run cleanly and reliably.
5. PHP Script Modernization
The kannel-monitor PHP script has been updated to support PHP 8.x, ensuring compatibility with modern PHP deployments.
The Results
The modernized Kannel is:
- Lighter: Removed thousands of lines of dead code
- Safer: Reduced attack surface, modern crypto, proper user isolation
- Easier: Simplified configuration without WAP options
- Modern: Systemd integration, OpenSSL 3.x compatibility
- Reliable: Fixed test suite ensures stability
Getting Started with Modern Kannel
Setting up the modernized Kannel is now straightforward:
# Clone the modernized version
git clone https://github.com/vaska94/kannel.git
cd kannel
# Install dependencies
# For Rocky Linux 10:
sudo dnf install gcc make autoconf automake libtool libxml2-devel \
openssl-devel pkgconfig mariadb-devel postgresql-devel \
sqlite-devel hiredis-devel
# For Arch Linux:
sudo pacman -S base-devel autoconf automake libtool libxml2 openssl \
mariadb-libs postgresql-libs sqlite hiredis
# Bootstrap the build system
autoreconf -fvi -I /usr/share/gettext/m4
# Configure with desired options
./configure --enable-ssl --with-ssl=/usr --disable-ssl-thread-test \
--with-mysql --with-pgsql --with-sqlite3 --with-redis \
ac_cv_sys_file_offset_bits=64
# Build and install
make -j4
sudo make install
# Set up systemd services
sudo ./contrib/systemd/setup-kannel-user.sh
sudo cp contrib/systemd/*.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable kannel-bearerbox kannel-smsbox
Platform Considerations
Developing on Arch Linux and deploying to Rocky Linux 10 highlighted some interesting platform differences:
- Arch’s rolling release meant I caught OpenSSL 3.5.0 compatibility issues early
- Rocky’s SELinux policies required careful attention to file contexts for the systemd services
- Package naming differences:
libxml2
vslibxml2-devel
,openssl
vsopenssl-devel
- Crypto policies: Rocky 10’s
FUTURE
crypto policy immediately rejected the old certificates
Lessons Learned
This modernization effort taught me several valuable lessons:
Don’t be afraid to delete code: Removing 10,000+ lines of WAP code made the project more maintainable, not less capable.
Systemd is a game changer: The old init.d scripts were so poorly designed that we had almost zero logging visibility. Systemd made everything more convenient - journalctl works beautifully, and I was able to split Kannel into two separate services (bearerbox and smsbox) with proper dependencies.
AI-assisted refactoring works: Claude AI was instrumental in understanding the complex interdependencies and safely removing legacy code. However, I didn’t just vibe coding with the AI - I carefully reviewed and tested every change. AI makes mistakes and misses details, but it’s incredibly helpful for accelerating development. What would have taken weeks was completed in a single night using Sublime Text, extensive grep searches, and AI assistance.
Tests are your safety net: The comprehensive test suite gave me confidence that SMS functionality remained intact.
Production Performance
I’ve tested this modernized Kannel extensively in production at Sender.ge, and the results speak for themselves:
- 5.5K requests per second on NVMe-based systems
- Rock-solid stability under sustained load
- Zero WAP-related overhead means more resources for SMS processing
- Valkey compatibility: Running in production with Valkey (Redis fork) instead of Redis with no issues
Kudos to the original Kannel development team for building such a solid foundation that’s still performant after 20+ years!
What’s Next?
With the WAP baggage gone, our Kannel fork can focus on what it does best: reliable SMS delivery. The immediate challenges ahead:
- Documentation overhaul: The docs still reference WAP extensively and need modernization
- Benchmark suite: Getting the existing benchmark suite to run properly (it’s there but needs fixing)
- SQLBox investigation: Haven’t touched SQLBox code yet - it should work out of the box, but I’ll investigate soon
- CI/CD pipeline: Create GitHub Actions workflow to automatically build packages
- Package repository: Build RPM packages for Rocky Linux 10 and set up a proper repository
- Better container support with proper signal handling
🏷️ Help Name This Project!
To avoid confusion with the original Kannel project, I’m considering renaming this modernized fork. Current ideas:
- KannelX - Simple, indicates “extended” version
- Kannel-Modern - Clear about purpose
- Your suggestion?
Got a better name? Drop your suggestions on X @vaska94 - contributions and ideas welcome!
The code is available at github.com/vaska94/kannel. If you’re running an old Kannel installation, consider upgrading to this streamlined version. Your ops team (and your security auditors) will thank you.
Final Note on AI Usage
Yes, I used AI to help write this article based on my thoughts and experiences. This is NOT an AI-generated article - I provided all the technical information, insights, and experiences, then carefully reviewed everything. I’m making the point that AI can have genuinely useful applications beyond creating junk vibe code. When you have the correct understanding of your domain and can carefully review every change to avoid weird modifications, AI becomes a powerful tool for real-world projects.
Have you modernized any legacy systems recently? What challenges did you face? Reach out on X @vaska94.