Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    Wireguard config over ssh

    Scheduled Pinned Locked Moved WireGuard
    8 Posts 2 Posters 1.9k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      mike_vc
      last edited by

      I'm looking to implement management of the wireguard service running on pfsense through scripting.
      I am particularly interested in adding and removing peers.
      I understand that I can issue commands via ssh to query existing peers, their assigned ips and even wg to add peers, but I'm not sure how to ensure that those peers are saved and that they appear properly in the wireguard configuration menu on the web gui.
      I see that there is also /usr/local/etc/wireguard/tun_wg0.conf which contains all peers and which I can edit, but adding a peer there doesn't seem to make it show up in the web gui either.

      Thanks,
      Mike

      S 1 Reply Last reply Reply Quote 1
      • S
        swinster @mike_vc
        last edited by swinster

        @mike_vc I have exactly the same question.

        I suspect that this is not a "supported" option, but for me, that is fine as I am looking to configure ephemeral pfSense VMs when automating some lab environments to create a Remote Access VPN (so adding clients automatically, but ideally also configuring the tunnel or resetting its private/public key). We have done this previously with an OpenVPN server installation on Ubuntu, but pfSense fits much better with the lab so makes much more sense to use it if possible (and pfSense is just great).

        I did start looking at Wireguard site itself (https://www.wireguard.com/quickstart/) but got distracted.

        If you come across anything, @mike_vc , I would be grateful if you would post back.

        S 1 Reply Last reply Reply Quote 0
        • S
          swinster @swinster
          last edited by

          One thing I can see being a little bit of an issue is when trying to add peers in a automated way is to ensure that the "Allowed IP" for the peer is configured correctly. It will just take a little bit of lateral thinking.

          S 1 Reply Last reply Reply Quote 0
          • S
            swinster @swinster
            last edited by swinster

            @mike_vc NOTE what I have done below is liable to cause all sort of issues if you get it wrong, but for me I still think there is value in figuring out this hacky way to do things. I managed to cause a couple of crashes through poor modification of the XML elements! BE WARNED!

            I have been playing around with the wg command (see https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8) and whilst you can create separate config files and even get them functioning using wg setconf or wg syncconf, as soon as you restart the WireGuard service of pfSense, the settings are reset to the original values. I even overwrote the conf file /usr/local/etc/wireguard/tun_wg0.conf, but this too is reset.

            The information looks to be stored in the /conf/config.xml file. There is a <wireguard>.....</wireguard> section which contains all of the configuration seen in the GUI. I have successfully hand updated the tunnel <privatekey>...</privatekey> and <publickey>...</publickey> elements, but you would need to modify the <peers>...</peers> section. I'm sure there would be a clever sh script out there that might be able to be modified to this, but I haven't looked yet. To update thei config.xml file, I used viconfig (although my vi skills are weak).

            It's also possible to control the WireGuard service via the command line, for example:

            Stop WireGuard service

            /usr/local/sbin/pfSsh.php playback svc stop WireGuard
            

            Start

            /usr/local/sbin/pfSsh.php playback svc start WireGuard
            

            So, whilst not there yet, it's a start!

            M 1 Reply Last reply Reply Quote 0
            • M
              mike_vc @swinster
              last edited by

              @swinster This might be what I was looking for. I wasn't aware of the /conf/config.xml containing the <wiregaurd> section.
              I'll play around with it and post back if I can figure out how to acquire "next available" ip, and add peer via that config.

              S 1 Reply Last reply Reply Quote 1
              • S
                swinster @mike_vc
                last edited by

                @mike_vc FWIW, I figured out that the "PHP Shell + pfSense tools" option might also help when editing the XML file, which is option 12 when login into the console/SSH as root/admin (although I think you can also run similar stuff from the standard shell using /usr/local/sbin/pfSsh.php). Also, see https://docs.netgate.com/pfsense/en/latest/development/php-shell.html

                For example, to set the config for the privatekey and publickey for the tunnel, I can run:

                $config['installedpackages']['wireguard']['tunnels']['item']['0']['privatekey'] = "XXXXXXXXXXXX";
                $config['installedpackages']['wireguard']['tunnels']['item']['0']['publickey'] = "YYYYYYYYYYYY";
                write_config();
                exec;
                playback svc restart WireGuard
                exit
                

                This sets the values of the relevant privatekey and publickey elements within config.xml, saves the config to disk, then restarts the WireGuard service (capitalisation is important, I found), and exits the PHP shell (apparently, you should only run one playback script for each PHP shell session, albeit you can run multiple playback scripts from the standard shell.

                After you have run these commands, you will see the update in the GUI. The changes will only come into effect once the WireGuard service has been restarted.

                I also found this post (https://serverfault.com/questions/790254/pfsense-shell-apply-config-modification-without-reboot) that might help in the construction of a shell script along with a PHP config script that edits arrays (which will be required for adding peers)

                Now, I am no Linux, PHP or Shell script expert. I am just muddling through but hopefully can build something to allow a script to be run by passing in the relevant peer keys via SSH and grabbing the server public key via SCP. I am much more comfortable in PowerShell and found this (https://www.powershellgallery.com/packages/pfSense/0.9.6), which I might be able to modify to do something similar, but I haven't looked too deeply yet.

                I am still concerned that you need to define a peer IP address within the tunnel (both on pfSense and in the client config). My lab client machines are identical clones, and I do not know what order they will connect in. I need some way to assign an IP within the tunnel range to be used by each client as it connects. It's a shame this doesn't happen automatically (I think it does in OpenVPN). Perhaps, I will have a simple text file with a pool of IPs on pfSense and remove one each time a client connects.

                I don't mind hacking like this because the entire lab gets reset and redeployed when done.

                S 1 Reply Last reply Reply Quote 0
                • S swinster referenced this topic on
                • S
                  swinster @swinster
                  last edited by

                  @mike_vc , dod you get anywhere with this?

                  M 1 Reply Last reply Reply Quote 0
                  • M
                    mike_vc @swinster
                    last edited by

                    @swinster
                    Here's as far as I've gotten so far. It's "seemingly" doing everything right, and not returning any errors, but then it also fails to create a new peer, and I haven't figured out where to go from here.
                    Mind that this is an interactive script that expects you to press Y, but should be easy to adopt to say take an email address as parameter instead and then email the config to that address.
                    It also assumes that you have a /24 subnet for your wireguard clients (for now).

                    #!/bin/sh
                    
                    DNS="10.2.10.10, mydomain.com"
                    ALLOWEDIPS="10.2.10.0/24"
                    ENDPOINT="wireguard.mydomain.com:51820"
                    
                    ## Usage
                    #./wg-add-peer.sh <username>
                    # check that only 1 argument is given
                    if [ $# -ne 1 ]; then 
                    	echo "illegal number of parameters\nUsage\n$0 <username>"
                    	exit 1
                    fi
                    
                    # Get tunnel name
                    tunnel=`xmllint --xpath "string(/pfsense/installedpackages/wireguard/tunnels/item/name)" /conf/config.xml`
                    
                    # Get the first 3 actets
                    subnet=`xmllint --xpath 'string(/pfsense/installedpackages/wireguard/tunnels/item/addresses/row/address)' /conf/config.xml | cut -f-3 -d'.'`
                    
                    # Get count of existing peers
                    peer_count=`xmllint --xpath "count(/pfsense/installedpackages/wireguard/peers/item)" /conf/config.xml`
                    
                    find_next_ip() {
                    # Assume the first integer in last octet belongs to our tunnel interface ip
                    seq=2
                    
                    # Find next available integer
                    for i in `xmllint --xpath "//pfsense/installedpackages/wireguard/peers/item//allowedips/row/address" /conf/config.xml | sed 's/<*.address>//g' | sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n | cut -f4 -d'.'`; do
                    	if [ $i != $seq ]; then
                    		echo $i
                                    return $i
                    	fi
                    	seq=$((seq+1))
                    done
                    echo $seq
                    return $seq
                    }
                    
                    next_ip="$subnet.$(find_next_ip)"
                    
                    #Generate keys
                    private_key=$(wg genkey)
                    public_key=$(echo "$private_key" | wg pubkey)
                    
                    
                    cat > /tmp/pfSsh_script.tmp << EOF
                    
                    \$newPeer['enabled'] = 'yes';
                    \$newPeer['tun'] = '$tunnel';
                    \$newPeer['descr'] = '$1';
                    \$newPeer['persistentkeepalive'] = '';
                    \$newPeer['publickey'] = '$public_key';
                    \$newPeer['presharedkey'] = '';
                    \$newPeerIP['address'] = '$next_ip';
                    \$newPeerIP['mask'] = '32';
                    \$newPeerIP['descr'] = '';
                    \$config['installedpackages']['wireguard']['peers']['item']][] = \$newPeer;
                    \$config['installedpackages']['wireguard']['peers']['item']['$peer_count']['allowedips']['row'][] = \$newPeerIP
                    pfSense shell: parse_config(true);
                    pfSense shell: write_config();
                    pfSense shell: exec;
                    playback svc restart WireGuard
                    exit
                    EOF
                    
                    cat > "$1-wg.conf" << EOL
                    [Interface]
                    PrivateKey = $private_key
                    Address = $next_ip/32
                    DNS = $DNS
                    
                    [Peer]
                    PublicKey = $(wg|grep "public key"|rev|cut -d' ' -f1|rev)
                    AllowedIPs = $ALLOWEDIPS
                    Endpoint = $ENDPOINT
                    PersistentKeepalive = 15
                    EOL
                    
                    echo "About to run the following pfSsh.php script:"
                    cat /tmp/pfSsh_script.tmp
                    read -r -p $'Confirm by pressing y...  ' key
                    
                    if [ "$key" == 'y' ] || [ "$key" == 'Y' ]; then
                    	/usr/local/sbin/pfSsh.php < /tmp/pfSsh_script.tmp
                    	rm -f /tmp/pfSsh_script.tmp
                    	echo "$1-wg.conf:"
                    	cat "$1-wg.conf"
                    else
                        # Anything else pressed, do whatever else.
                        echo User input not y...
                    	exit 1
                    fi
                    
                    
                    
                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post
                    Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.