Packaging¶
.ipk for OpenWrt ≤24.10 (opkg), .apk for 25.x+ (apk). Both are built from the same payload
by scripts/ipk/build-ipk.sh and scripts/apk/build-apk.sh.
./scripts/ipk/build-ipk.sh <version> <openwrt_arch> <binary_dir> [luci_dir] [output_dir]
./scripts/ipk/build-ipk.sh 1.33.1 aarch64_generic ./binaries
luci_dir defaults to luci-app-nym-vpn/ in the repo, output_dir to the current directory. The
script checks every required file is present, assembles the tree, computes installed size from
du -sk, fills in the control template, and emits nym-vpn_{version}_{arch}.ipk.
What's in it¶
nym-vpn_1.33.1_aarch64_generic.ipk (tar.gz)
├── debian-binary # "2.0"
├── control.tar.gz
│ ├── control # generated from control.template
│ ├── conffiles # /etc/config/nym-vpn
│ ├── postinst
│ └── prerm
└── data.tar.gz
├── usr/sbin/nym-vpnd
├── usr/sbin/nym-vpn-watchdog
├── usr/bin/nym-vpnc
├── usr/libexec/rpcd/nym-vpn
├── www/luci-static/resources/view/nym-vpn/*.js
├── www/luci-static/resources/nym-vpn/*.js
├── etc/init.d/nym-vpnd
├── etc/init.d/nym-vpn-watchdog
├── etc/config/nym-vpn
├── etc/uci-defaults/luci-app-nym-vpn
├── etc/nym/data/ # empty, for daemon state
├── usr/share/luci/menu.d/luci-app-nym-vpn.json
├── usr/share/rpcd/acl.d/luci-app-nym-vpn.json
├── usr/share/nym-vpn/fw3-include.sh
├── usr/share/nym-vpn/fw4-include.sh
├── etc/opkg/keys/<fingerprint>
└── etc/apk/keys/dial0ut.pub
The opkg key is installed under its fingerprint, not its filename — build-ipk.sh derives it
by base64-decoding the second line of scripts/feed/dial0ut.pub and taking bytes from the header.
usign looks keys up that way.
etc/uci-defaults/luci-app-nym-vpn runs once on first boot after install. It is what registers
the firewall include, so the kill-switch survives fw4 reload.
Dependencies come from scripts/ipk/control.template, and build-apk.sh repeats the same list:
| Package | Why |
|---|---|
libc |
musl libc |
kmod-tun |
TUN device for userspace WireGuard |
libmnl |
netlink — the binaries link against it |
libnftnl |
nftables netlink — likewise |
kmod-ipt-conntrack-extra |
conntrack marking for inbound exemptions on fw3 |
luci-base |
LuCI web framework |
rpcd |
RPC backend for LuCI |
For apk these go in a single -I "depends:..." flag. Repeated -I depends: flags overwrite
each other rather than accumulating — every .apk up to 1.30.5 shipped depending on rpcd alone,
so kmod-tun was never pulled in and the daemon died at TUN device creation.
postinst¶
- TUN device —
mknod /dev/net/tun c 10 200if it does not already exist - Feed registration — reads the architecture from
/etc/openwrt_release, falling back to/etc/os-releasesince not every image ships both. Then:- apk: removes any stale nym-vpn lines from
/etc/apk/repositoriesand/etc/apk/repositories.d/*.list, then writes/etc/apk/repositories.d/nym-vpn.list - opkg: appends a
src/gz nym-vpnline to/etc/opkg/customfeeds.conf
- apk: removes any stale nym-vpn lines from
- Service — enables and starts
nym-vpnd. Ifnym-vpn.settings.always_onis already1(i.e. this is an upgrade), enables and startsnym-vpn-watchdogtoo. - rpcd restart — so the new ACLs load
- Prints both upgrade commands,
opkgandapk, without picking between them
prerm¶
Steps 1–3 run on every removal including upgrades. The rest is gated on PKG_UPGRADE != 1,
so an upgrade does not tear down state the incoming version is about to reuse.
- Stop
nym-vpn-watchdogandnym-vpnd, disable both - Firewall cleanup — the part that matters. fw4:
nft delete table inet nym, then walk fw4's own chains deleting rules taggednym-vpn:by handle. fw3: remove jump rules from the hook chains, flush and delete theNYM_*chains, delete the NAT POSTROUTING masquerade rules by line number. Skip this and an uninstall leaves the kill-switch up with nothing to take it down. - Stray routing rules — flush any
ip ruleentries matching the daemon's fwmarks, v4 and v6. The daemon normally clears these itself on stop; a crashed one does not. Matching on fwmark rather than priority avoids touching unrelated rules. - UCI — delete the
firewall.nym_vpninclude and commit - Temp files — the saved firewall rulesets, the adblock dnsmasq drop-in, DNS backups, the watchdog state file
Then, full removal only:
- DNS — revert
dhcp.@dnsmasq[0].resolvfileto stock, remove the managed resolv file, and restart dnsmasq only if the running instance still points at the file just deleted. On upgrade none of this happens: the new daemon reconverges without a restart, and restarting dnsmasq here would be a LAN-wide DNS outage for no reason. - Data —
rm -rf /etc/nymand/var/log/nym-vpnd - Feed — strip nym-vpn lines from
customfeeds.conf, remove/etc/apk/repositories.d/nym-vpn.list
conffiles¶
/etc/config/nym-vpn is marked as a config file, so an upgrade keeps your version and writes new
defaults to .new alongside it.
The shipped default:
config nym-vpn 'settings'
option enabled '0'
option network 'mainnet'
option always_on '0'
option watchdog_interval '30'
option watchdog_max_retries '3'
Disabled on install — you enable it from LuCI or the CLI.