Decentralize common Fedora apps with Cjdns

Are you worried about a few huge corporations controlling the web? Don’t like censorship on centralized social media sites like facebook and twitter? You need to decentralize! The internet was designed to be decentralized. Many common activities, from social media to email to voice calls, don’t actually require a centralized service.

The basic requirement for any peer to peer application is that the peers be able to reach each other. This is impossible today for most people using IP4 behind NAT (as with most household routers). The IP4 address space was exhausted over a decade ago. Most people are in “IP4 NAT Jail.”

Your device is assigned a private IP, and translated to the public IP by the router. Without port forwarding to a specific private IP, incoming TCP connections or UDP sessions can’t tell where to forward to, and are dropped. As a result, nothing can connect to your device. You must connect to various public servers to do anything. IP4 NAT Jail forces centralization.

The simplest solution to this problem is IPv6. However, most US consumer internet providers do not offer usable IPv6. For instance, if the IPv6 prefix changes every few days, the devices are not addressable except via a dynamic DNS server. Furthermore, on a mobile device like a laptop, most WiFi does not offer IPv6 either. So you can’t use Mobile IP6 to have a stable address.

You can work around this using a VPN like OpenVPN (included in Fedora) to a centralized server with a public IP4 — perhaps one you provide yourself by renting a Virtual Personal Server. But then packets to and from your device have to travel to and from the VPN server first. You can also use a tunnel broker like

If you and your peers already have stable IPv6 addresses, you can use these for the sample applications to be showcased. But most people need to use something else.

DNS is also essentially a centrally controlled service, so this article’s two sample applications avoid the use of DNS.  Email and SIP applications have built-in address books that work just as well.  Think of your stable IPv6 address as a “phone number.”

IPv6 Overlay Mesh VPN with Cjdns

The Cjdns package (included in Fedora) implements a global IPv6 mesh by connecting to several peers instead of a centralized server. Each node has a public/private key pair. The IPv6 is the truncated SHA512 hash of the public key, preventing spoofing.

  • Packets are end to end encrypted — relays can be untrusted.
  • Packets are source routed, allowing seamless upgrades of and experimentation with routing algorithms.  (This is safe thanks to anti-spoofing.)
  • The data for routing comes from a Distributed Hash Table listing the peers of each node.
  • Peers can be explicitly configured as UDP tunnels, or auto-configured on ethernet via layer 2 protocol 0xfc00.

With Cjdns installed, you have a stable, “unspoofable” (standard cryptographic caveats apply) IPv6 address that can be used with any IPv6 ready application. Your recipient must also use the Cjdns protocol, but this isn’t much of an obstacle since it’s easier to install Cjdns than convince US ISPs to provide usable IPv6.

Install Cjdns

To install and enable the Cjdns service persistently, run these commands:

$ sudo dnf install cjdns cjdns-tools cjdns-selinux
$ sudo systemctl enable --now cjdns
$ peerStats
18:03:14:56:c2:1e v20.0000.0000.0000.0019.681v1s7k3af1q2cf09txpw309zdf4q0mn7mtq0wr544dz98stwr0.k ESTABLISHED in 6kb/s out 15kb/s  LOS 8 "outer"

This generates a /etc/cjdroute.conf file, pre-populated with random keys and passwords. If there’s already a Cjdns node on your LAN as above, you’re done. But more likely, there was no output from peerStats. In that case you now need to configure one or more UDP tunnels. First, you must discover the random UDP port used.

$ sudo grep bind /etc/cjdroute.conf
        // Port to bind the admin RPC server to.
        "bind": "",
                "bind": "",
                "bind": "[::]:26041",
        // Alternatively bind to just one device
                "bind": "all",

In this example, the random UDP port is 26041 for both IPv6 and IPv4. Your port will be different. Allow incoming sessions for this port.

$ sudo firewall-cmd --zone=public --add-port=26041/udp
$ sudo firewall-cmd --runtime-to-permanent

Now you need to edit the config to add a peer. Hopefully, you are somewhat familiar with configs using JSON syntax. You must add an entry for a UDP peer using your favorite text editor, such as vim. Here is one provided on a VPS. Search for IPv4, and add the indicated stanza after connectTo, inside the braces:

$ sudo vim /etc/cjdroute.conf
"": {
    "login": "fedora",

For the changes to take effect, restart cjdns.

$ sudo systemctl restart cjdns
$ peerStats v20.0000.0000.0000.0017.lhj54c2xnczfurpw42d0h1bvc4qquclb4dw72q50tc83ucmm9zt0.k ESTABLISHED in 0kb/s out 0kb/s ""
$ ping
PING (fceb:7fc0:c62c:9cd9:2971:e3ff:aee2:6e08)) 56 data bytes
64 bytes from (fceb:7fc0:c62c:9cd9:2971:e3ff:aee2:6e08): icmp_seq=1 ttl=42 time=87.6 ms

You can now ping any node in the global IPv6 mesh. CAUTION: All those nodes can now directly connect to your device. The default Fedora firewall will block all incoming connections be default — but be careful what you allow in. Be sure to consult the package README for additional security notes.

The fedora password to this nyc VPS may not be up indefinitely, so you need some more peers. Consult a list of public peers or peer with your Fedora friends.

Decentralize Email applications

You can decentralize almost any email client included in Fedora that supports IPv6, such as alpine or Thunderbird. This example uses mailx, a bare bones CLI mail client designed for teletypes. This makes configuration and use easy to show.

Similarly, you can use any of the MTAs supplied with Fedora, but this example uses opensmtpd, as it is simple, small, and secure. By default, opensmtpd stores incoming email in /var/spool/mail, which is perfect for personal decentralized use. You can, of course, use any mail store and client you prefer.

$ sudo dnf install mailx opensmtpd
$ cat >~/.mailrc <<EOF
set from="mylogin@[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678] (Real Name)"
set smtp=localhost

Of course, you need to use your own local login, IPv6 and name.

To receive email, you will need to edit the opensmtpd config in /etc/opensmtpd/smtpd.conf. Here is a sample. (Note this article may wrap some of the “preformatted” lines, so try this link for a working config if needed):

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

# To accept external mail, replace with: listen on all
listen on fc02:fefe:dead:beef:cafe:babe:1234:5678 hostname "[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678]"
listen on localhost

# If you edit the file, you have to run "smtpctl update table aliases"
table aliases file:/etc/aliases

# Uncomment the following to accept external mail for domain ""
#accept from any for domain "" alias  deliver to mbox
accept from any for domain "[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678]" alias  deliver to mbox

accept for local alias  deliver to mbox
accept for any relay hostname "[IPv6:fc02:fefe:dead:beef:cafe:babe:1234:5678]"

Use your actual Cjdns IP, of course. When the opensmtpd config is ready, start it so you can receive emails. If your recipient is offline, opensmtpd stores your letter and retries periodically.

$ sudo systemctl enable --now opensmtpd
$ sudo firewall-cmd --zone=public --add-service=smtp
$ sudo firewall-cmd --runtime-to-permanent

Now send the author a dex (decentralized) email:

$ mailx -s "Fedora Article" \
  "stuart@[IPv6:fcbc:b27:be6f:94dd:4225:792:c988:8ace]" <<EOF
> Great article!

That sends an email to the author’s nyc vps — so don’t be surprised if you get a reply!

Alpine is a full featured console email client. After you install and run it the first time, you can decentralize it by editing ~/.pinerc and changing these basic config items:

# Sets domain part of From: and local addresses in outgoing.
# List of SMTP servers for sending mail.

Decentralize SIP applications

Linphone call screen

Linphone call screen

Using Cjdns for your voice calls gives you privacy and authentication. You can use any sip client that supports IP6. This example uses the linphone app included in Fedora.

$ sudo dnf install linphone
$ sudo firewall-cmd --zone=public --add-service=sip --add-port=7078/udp --add-port=9078/udp
$ sudo firewall-cmd --runtime-to-permanent
Linphone network config screen

Linphone network config screen

Run linphone on your desktop, and skip the account wizard. You don’t need logins and accounts with peer to peer. Select Options, Preferences and select Use IPv6 instead of IPv4 and Direct connection to internet. Enter your Cjdns IPv6 in Public IP address. Now select Options, Quit to completely exit linphone.

The version in Fedora doesn’t provide a way to configure your peer to peer contact, so you need to edit the config file. Find the [sip] section and change guess_hostname and contact:

$ vim ~/.linphonerc
contact="Real Name" <sip:mylogin@[fc02:fefe:dead:beef:cafe:babe:1234:5678]>

Now start linphone again, and add a Fedora friend with Cjdns to the addressbook using the same address syntax. Try a text message first, then give them a call.

Of course, there are many potential issues with audio and video in a VoIP app, which are not covered here. Usually, however, linphone just works. If you don’t have any friends, you can reach out to the author via dex email at the nyc node above.

Fedora Project community Using Software


  1. I forgot to tell the audience how to find out their Cjdns IP. There are many ways, from “ip addr” to “ifconfig”. But had I remembered, I would have suggested:

    $ sudo grep ipv6 /etc/cjdroute.conf

  2. Sugreeva

    Thanks for a very informative article…

    If our node is already under a Firewall / router that uses IPV4, how we can set these things to reach to IPV6 mesh ? How we can check whether our router / Firewall is IPV6 enabled ?

    Do national gateways uncensor this Tunnel Brokering ? What about the observations or news of Tunnel brokering in countries like China ?

    Thanks again…

    • Your question lacks specifics, so my answers are necessarily conditional…

      An external firewall cannot affect Cjdns except to block the UDP tunnel traffic completely. Cjdns is end-to-end encrypted. If you can get one or more Cjdns peer connections up, then any national/ISP/home router firewalls are irrelevant. Because Cjdns uses a random UDP port, it is difficult for an external firewall to block without blocking all UDP traffic.

      China already uses IPv6 – they are way beyond US in that respect. I doubt the Chinese national firewall allows tunnel brokers. Furthermore, while it is no doubt technically possible to bypass their national firewall – that is not the only enforcement method, and I am in no position to advise any course of action.

      If you are running Fedora, the default internal firewall frontend is “firewalld”. (Which is piggy – but that is another conversation.) Firewalld by default affects IPv4 and IPv6 simultaneously. You need special “rich rules” in firewalld to affect only one or the other.

      Home routers running open software like LEDE/OpenWRT (and others I am not familiar with) can certainly handle IPv6 and connect to tunnel brokers like when needed. Configuring a specific one is it’s own article – and not a Fedora article. Check out for the distro I use on my home routers. My main router at home is actually a Dell server running CentOS (and VMs running various things including Fedora). It could also run Fedora – and configuring a Fedora based router as a gateway for conventional IPv6 would be a good Fedora Magazine article. It is a good idea to start with the “minimal” installation for that kind of application, and add packages as needed.

      Because Cjdns is end-to-end encrypted, there can be no Cjdns “gateway”. However, Cjdns has a built-in ipTunnel, so that your router could partner with another Cjdns node to route conventional IPv4 and IPv6 traffic to/from your home network. This is functionally no different than using something like OpenVPN for the same purpose (but is harder for external firewalls to block). There are, in fact, commercial services providing VPN service via Cjdns.

      While I have no experience with other parts of the world, I can tell some funny stories about US “traffic shaping” by corporate ISPs. E.g. I found in my case that their shaping (aka “throttling”) fails to notice 6in4 packets (used by unencrypted tunnel brokers like, and therefore downloads were effectively faster with tunneled IPv6!

  3. rawfox

    awesome <3

  4. Mehdi

    Great article!

  5. Sugreeva

    Thank you man… Keep it up. we are waiting for your own “Fedora articles” mentioned by you here… May be a router with IPTABLES in detail with respect to IPV4 and IPV6.

  6. Several readers have sent me dex emails, and I replied, but the replies are still queued as port 25 is not open for incoming connections on the devices (although the devices are responding to pings).

    In the interest of instruction on the security aspects, I ran nmap on one of the Cjdns ips that sent me a dex email, getting this report (sans the actual IP):

    Host is up (0.19s latency).
    Not shown: 844 closed ports, 154 filtered ports
    22/tcp open ssh
    3689/tcp open rendezvous

    Nmap done: 1 IP address (1 host up) scanned in 39.10 seconds

    This is all fine if you are expecting those to be public. For instance, 3689/tcp is normally used for iTunes™ – and if it is actually an itunes clone (I didn’t investigate further), maybe you don’t really want to be opening it to the public?

    Similarly, when exposing SSH (port 22) to the public, you might want to restrict which accounts can login via SSH (in /etc/ssh/sshd_config). E.g. you might want AllowUsers and/or PermitRootLogin without-password.

  7. Diego A. Casas

    Thank you

    I used the OpenSMTPD config sample you provide, but smtpd had issues parsing it.






    solved the problem.

  8. Steve

    Hello Stuart,

    Thank you for a very informative article. I was able to set up CJDNS relatively easily, even connected to your provided link and a public one from the list at Git. Are there specific sites that use this tool, or is it more prevalent in the higher learning centers. It seems to be geared towards anonymity.

    • Cjdns is not anonymous. The contents of the packets are encrypted, but your Cjdns IP is public, and it is not hard for a determined sleuth to find the geographic location whence packets for the IP originate. There is no obfuscating routing like with Tor. Hence, Cjdns often performs better than clearnet (when clearnet operators do a particularly bad job).

      An http web site is a centralized service – that is what dex apps are trying to avoid. Sometimes HTTP is used for local information, e.g. you can fetch some info about the nyc node at http://[fcbc:b27:be6f:94dd:4225:792:c988:8ace]/nodeinfo.json
      or if you trust DNS.

      You are much more likely to find nodes for more decentralized protocols like IRC. E.g. you can use with hexchat (or pidgin) to get on a hyperboria IRC network. Fully dex apps like the peer to peer email and SIP demonstrated in the article have no servers at all. Other dex protocols common on hyperboria include Secure ScuttleButt and matrix.

  9. I was able to reply to only one dex email. Others apparently were not able to reconstruct the opensmtpd config from the mangled remnants left by WordPress. Once you have Cjdns up, you can fetch:


    to get a working opensmtpd config. Change the Cjdns IP to your own.

    • Another reader has identified a more likely culprit: the opensmtpd.service needs to wait for cjdns to be online before starting. Systemd attempts to start opensmtpd before Cjdns has the tunnel ready. To fix this, copy the service file to /etc/systemd/system:

      $ sudo cp /usr/lib/systemd/system/opensmtpd.service /etc/systemd/system
      $ sudo vi /etc/systemd/system/opensmtpd.service

      Add cjdns-wait-online.service to the After= config:

      — opensmtpd.service 2018-01-27 17:06:40.000000000 -0500
      +++ /etc/systemd/system/opensmtpd.service 2018-08-15 20:27:56.005683778 -0400
      @@ -1,6 +1,6 @@
      Description=OpenSMTPD mail daemon cjdns-wait-online.service
      Conflicts=sendmail.service postfix.service exim.service


  10. New search engin is online! See the site below:

    • Very interesting, thanks! I’ve already used it. But now, I proceed to examine the mouth of the gift horse.

      It does not seem to be available via Cjdns
      The links all go through the proxy – I would expect only the “View via proxy” link to do through the proxy.
      When I tried the proxy, it didn’t seem to work.

      However, I am able to copy & paste the links into a browser tab and view the targets.

      Finally, although it very useful, all us dex people are thinking, “This is how google got started. It is small, volunteer, a valuable service – but inherently centralized.” I wonder if a dex search protocol could be designed? E.g., blue sky idea: all sites that want to be searchable publish DHT search records signed by the IP they are available on. Participants would ignored invalid signatures. I can already think of some problems, with that idea – but maybe it will start a conversation.

Comments are Closed

The opinions expressed on this website are those of each author, not of the author's employer or of Red Hat. Fedora Magazine aspires to publish all content under a Creative Commons license but may not be able to do so in all cases. You are responsible for ensuring that you have the necessary permission to reuse any work on this site. The Fedora logo is a trademark of Red Hat, Inc. Terms and Conditions