A practical guide to running the SoftEther VPN Client on Ubuntu without a GUI. The official Connection Manager GUI is Windows-only, so on Linux the client is managed with vpncmd.
This guide covers:
- Installing the SoftEther VPN Client
- Creating and configuring a VPN connection
- Creating the virtual network adapter
- Obtaining a VPN address through DHCP
- Split-tunnel routing
- Managing the connection with a simple
vpnCLI script - Monitoring connection status and routes
- Troubleshooting common problems
Tested on: Ubuntu 26.04, SoftEther VPN Client v4.44 build 9807
Placeholders: Replace values such as<VPN_ACCOUNT>,<SERVER_IP>,<PORT>,<HUB>, and<USERNAME>with the values provided by your VPN administrator.
- Prerequisites
- Install the client
- One-time configuration
- Obtain an IP address (DHCP)
- Routing and split tunneling
- Starting the SoftEther client
- Control script:
vpn up | down | status - Monitoring and logs
- Troubleshooting
- Security notes
sudo apt update
sudo apt install -y build-essential isc-dhcp-clientisc-dhcp-clientprovidesdhclient.build-essentialis only required if compiling the SoftEther client from source.
Verify:
dhclient --versionDownload the Linux / SoftEther VPN Client package from the official SoftEther download page.
Extract and build it:
tar xzf softether-vpnclient-*-linux-x64-64bit.tar.gz
cd vpnclient
makeAccept the license terms when prompted.
Then install it:
cd ..
sudo mv vpnclient /usr/local/
sudo chmod 600 /usr/local/vpnclient/*
sudo chmod 700 /usr/local/vpnclient/vpnclient
sudo chmod 700 /usr/local/vpnclient/vpncmdVerify:
ls -lah /usr/local/vpnclientYou should see files such as:
vpnclient
vpncmd
hamcore.se2
The two important executables are:
/usr/local/vpnclient/vpnclient
/usr/local/vpnclient/vpncmd
Start the SoftEther VPN Client:
sudo /usr/local/vpnclient/vpnclient startThen open the management console:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENTInside vpncmd, create the virtual adapter:
NicCreate VPN
Create the VPN connection:
AccountCreate <VPN_ACCOUNT> /SERVER:<SERVER_IP>:<PORT> /HUB:<HUB> /USERNAME:<USERNAME> /NICNAME:VPN
Set the password:
AccountPasswordSet <VPN_ACCOUNT> /TYPE:standard
AccountPasswordSet without /PASSWORD: makes vpncmd prompt for the password, so the password is not exposed in shell history or the command line.
Connect:
AccountConnect <VPN_ACCOUNT>
Check the connection:
AccountStatusGet <VPN_ACCOUNT>
A successful connection should report:
Session Status | Connection Completed (Session Established)
From the normal shell:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD AccountListThe output should contain your configured VPN connection setting.
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD NicListThe SoftEther adapter in this guide is named:
VPN
On Linux, this appears as:
vpn_vpn
Verify it:
ip -br linkExpected:
vpn_vpn UNKNOWN ...
An established SoftEther session provides a Layer-2 connection, but the Linux interface still needs an IP address.
Run:
sudo dhclient -v vpn_vpnThen:
ip -br a show vpn_vpnYou should see an address assigned to the VPN interface.
If no DHCP lease is received, the VPN hub may not provide DHCP.
In that situation, ask the VPN administrator for the appropriate static configuration.
For a static address:
sudo ip addr add <VPN_IP>/<PREFIX> dev vpn_vpnThis setup uses split tunneling.
Normal Internet traffic continues to use the physical network connection, while specific internal networks are routed through the VPN.
Check the default route:
ip routeFor example:
default via <LOCAL_GATEWAY> dev <PHYSICAL_INTERFACE>
This means Internet traffic is not automatically sent through the VPN.
Check where a public destination will go:
ip route get 1.1.1.1It should use your normal network interface.
VPN-specific routes may look like:
<INTERNAL_NETWORK_1> via <VPN_GATEWAY> dev vpn_vpn
<INTERNAL_NETWORK_2> via <VPN_GATEWAY> dev vpn_vpn
<INTERNAL_HOST> via <VPN_GATEWAY> dev vpn_vpn
Check the complete routing table:
ip routeCheck which interface will be used for a particular destination:
ip route get <INTERNAL_HOST_IP>The result should use:
dev vpn_vpn
If an internal host is not automatically routed through the VPN:
sudo ip route add <INTERNAL_HOST_IP>/32 via <VPN_GATEWAY> dev vpn_vpnFor an entire network:
sudo ip route add <INTERNAL_NETWORK>/<PREFIX> via <VPN_GATEWAY> dev vpn_vpnDo not blindly delete the default route through the VPN.
If your goal is split tunneling, the normal default route should remain on the physical network interface.
This setup can run the SoftEther daemon directly without requiring a systemd service.
Start the daemon:
sudo /usr/local/vpnclient/vpnclient startThen connect the account:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD AccountConnect <VPN_ACCOUNT>Check the connection:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD AccountStatusGet <VPN_ACCOUNT>To disconnect:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD AccountDisconnect <VPN_ACCOUNT>If you want the SoftEther daemon to start automatically at boot, create:
/etc/systemd/system/vpnclient.service
with:
[Unit]
Description=SoftEther VPN Client
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
ExecStart=/usr/local/vpnclient/vpnclient start
ExecStop=/usr/local/vpnclient/vpnclient stop
[Install]
WantedBy=multi-user.targetThen:
sudo systemctl daemon-reload
sudo systemctl enable --now vpnclientCheck:
systemctl status vpnclientThe control script below does not require this systemd service. It starts the SoftEther daemon directly.
A small shell script makes the VPN easier to manage.
Create:
mkdir -p ~/bin
nano ~/bin/vpnMake sure ~/bin is in your PATH:
echo "$PATH" | tr ':' '\n' | grep -Fx "$HOME/bin"If it is not:
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcMake the script executable:
chmod +x ~/bin/vpn#!/usr/bin/env bash
# vpn - manage a SoftEther VPN Client connection
set -euo pipefail
ACCOUNT="<VPN_ACCOUNT>"
IFACE="vpn_vpn"
VPNCMD=(
sudo
/usr/local/vpnclient/vpncmd
localhost
/CLIENT
/CMD
)
wait_for_iface() {
for _ in {1..15}; do
if ip link show "$IFACE" &>/dev/null; then
return 0
fi
sleep 1
done
echo "Interface $IFACE did not appear" >&2
return 1
}
case "${1:-}" in
up)
sudo /usr/local/vpnclient/vpnclient start
sleep 2
"${VPNCMD[@]}" AccountConnect "$ACCOUNT" >/dev/null
wait_for_iface
sleep 3
if ! ip -4 addr show "$IFACE" | grep -q '<VPN_SUBNET_PREFIX>'; then
sudo dhclient -v "$IFACE"
fi
echo "VPN is up."
;;
down)
sudo dhclient -r "$IFACE" 2>/dev/null || true
"${VPNCMD[@]}" AccountDisconnect "$ACCOUNT" >/dev/null
echo "VPN is down."
;;
status)
"${VPNCMD[@]}" AccountStatusGet "$ACCOUNT"
echo
ip -br a show "$IFACE"
echo
echo "Routing:"
ip route
;;
*)
echo "usage: vpn {up|down|status}" >&2
exit 1
;;
esacReplace
<VPN_SUBNET_PREFIX>with the VPN subnet prefix appropriate for your environment, for example192.168.x.. Alternatively, remove the address check and always rundhclient.
Connect:
vpn upCheck status:
vpn statusDisconnect:
vpn down- Starts the SoftEther VPN Client daemon.
- Connects the configured VPN account.
- Waits for the virtual adapter.
- Checks whether the adapter already has an IPv4 address.
- Runs DHCP if necessary.
- Leaves the normal Internet default route untouched.
- Releases the DHCP lease.
- Disconnects the SoftEther VPN account.
- Leaves the SoftEther daemon running.
Keeping the daemon running makes the next:
vpn upsimpler because only the VPN connection itself needs to be re-established.
Displays:
- SoftEther session status
- VPN server information
- Encryption information
- Session statistics
- Traffic statistics
- VPN interface address
- Current routing table
vpn statusOr directly:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD AccountStatusGet <VPN_ACCOUNT>A successful connection contains:
Session Status | Connection Completed (Session Established)
ip -br a show vpn_vpnip routeip route get <IP>ip monitor linksudo tail -f /usr/local/vpnclient/client_log/*.logOnly relevant if you install the optional systemd service:
journalctl -u vpnclient -fCheck:
command -v vpnIf ~/bin is missing from PATH:
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcThen:
command -v vpnExpected:
/home/<USER>/bin/vpn
If you are not using the optional systemd configuration, start the client directly:
sudo /usr/local/vpnclient/vpnclient startThe control script already uses this method.
List configured accounts:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD AccountListMake sure the account name in the script matches the configured connection:
ACCOUNT="<VPN_ACCOUNT>"Install:
sudo apt install isc-dhcp-clientCheck:
ip -br a show vpn_vpnThen:
sudo dhclient -v vpn_vpnIf DHCP fails, the VPN hub may not provide DHCP.
Check:
ip -br linkThen check the SoftEther adapters:
sudo /usr/local/vpnclient/vpncmd localhost /CLIENT /CMD NicListThe expected SoftEther adapter is:
VPN
which appears on Linux as:
vpn_vpn
Check:
ip route get <INTERNAL_HOST_IP>The route should use:
dev vpn_vpn
If another interface wins, add an explicit route if appropriate:
sudo ip route add <INTERNAL_HOST_IP>/32 via <VPN_GATEWAY> dev vpn_vpnThis is expected with split tunneling.
Check:
ip route get 1.1.1.1The result should use your normal physical network interface.
If your Git server is only reachable through the VPN, disconnecting the VPN will make it unreachable.
Check:
ip route get <GIT_SERVER_IP>With the VPN connected, the route should use:
dev vpn_vpn
- Never pass passwords on the command line using
/PASSWORD:.... - Use
AccountPasswordSetinteractively so credentials do not appear in shell history. - If a password is accidentally exposed in a terminal log, chat, ticket, or repository, rotate it.
- Keep
/usr/local/vpnclientrestricted to root where practical. - Do not commit VPN credentials to Git.
- Do not publish real VPN server addresses, usernames, session keys, internal addresses, or other connection details in public repositories.
- Avoid publishing complete
AccountStatusGetoutput because it may contain connection-specific information.