Setting up OpenVPN plus DDNS access

Hey guys,
Just updated to 18.06 and thought I take it as an opportunity to do a proper set-up.

I have a VPN access by ExpressVPN which I would like to use on my router to mask my whole network. I did that on LEDE before and that worked well (with some hacks and inconveniences but it worked reliably).
What I have always missed is that you naturally loose the ability to have remote SSH access via DDNS.

  1. Is it possible to have both?
  2. If yes, how?

Static route to your DDNS "delivery target" that goes "direct" and not through the tunnel, assuming that it's the type that determines your IP address from where the connection comes, not from the content that you deliver there.

If your DDNS provider can accept the IP address to register from the content you send them, then you "just" need to determine your IP address (and may be able to go through the VPN portal, assuming they don't enforce agreement between the source and the specified IP address).

One way to do this is with

ip -4 addr show dev <interface name> | sed -nEe 's/^.*inet ([0-9.]+)\/.*$/\1/p'

(I'm assuming that if you have IPv6, it's not dynamic and you manage its DNS in other ways.)

Hey jeff,

Ho, slowly, my regexp-fu is not that sophisticated. Thanks for the idea though. What is that command doing?

Goal

Find the line in the output of the ip command that has the IPv4 address, extract the address, and output just the address on stdout


sed -- string search and replacement utility
-n -- don't automatically print every line that comes through
-E -- use "extended" or "modern" regexp syntax
-e -- execute the following string as a command/pattern
'...' -- protect the string from shell expansion
s/.../.../ -- substitute the first pattern for the second
s/.../.../p -- the p says to print it if it matches

First Pattern

^ -- match beginning of the line
^.*inet -- beginning of the line followed by any number of characters, the string inet, followed by a space
(...) -- "remember" if this matches
([0-9.]+) -- remember the match of one or more digits or periods
\/ -- followed by a slash (escaped with a backslash, so it isn't interpreted as the divider between the two patterns
.* -- then any number of any characters
$ -- to the end of the line -- so I've now matched the entire line

Replacement Pattern

\1 -- use the first remembered match from the first pattern to replace everything matched by the first pattern

Yes, definitely possible. I'm using the package VPN Policy Routing for this.

Set up a default policy for ExpressVPN to route all your network traffic through the VPN tunnel. Set up another policy to capture your DDNS update requests and SSH traffic, and route them through your WAN interface. That way you can approach your WAN IP by your DDNS hostname, and open up SSH and all other services you want to access remotely.

Should be pretty straight forward to set up. Note that the order of the policies matters: if a ruleset matches, all policies below will be skipped. You also need to set up port forwarding from WAN > LAN.

I've stumbled over something similar, VPN Bypass.
I screwed up something in my network yesterday and will have to spend some time to properly set things up but I'll check that out. I'll be back once my printer talks to all/any of my devices again. :slight_smile:

You probably don't need anything fancy at all for the DDNS update, at least as I read the API at https://www.noip.com/integrate/request

http://username:password@dynupdate.no-ip.com/nic/update?hostname=mytest.testdomain.com&myip=1.2.3.4

Given that you can specify the name and address both, you should be able to perform the update through the VPN tunnel.

Something along the lines of

#!/bin/sh

currentip=$(ip -4 addr show dev <interface name> | sed -nEe 's/^.*inet ([0-9.]+)\/.*$/\1/p')
if [ ! "${currentip}" ] ; then
    curl http://username:password@dynupdate.no-ip.com/nic/update\?hostname=mytest.testdomain.com&myip=${currentip} && \
        logger -t DDNS_UPDATE -p daemon.info Sent ${currentip} || \
        logger -t DDNS_UPDATE -p daemon.err ERROR sending ${currentip}: $?
else
    logger -t DDNS_UPDATE -p daemon.warning WARNING no current IP found. No update performed.
fi

(untested, but should be close)

You would likely have to modify the routing for your local ssh server as the return packets would otherwise go out the VPN, likely being aliased to the VPN remote portal address, rather than your "real" IP address.

Okay, wonderful, that solves part of the issue. I'm back, I had a problem with my WiFi driver.

Let's maybe start with being able to SSH into my public address. DDNS updates are then a trivial second step.
I looked into VPN Policy routing and did what you mentioned @ralpho, but I could not dial in.
I created a policy 'SSH' with the following rather simple setup:

config policy
        option interface 'wan'
        option comment 'SSH'
        option local_ports '22'
        option remote_ports '22'
        option local_addresses '192.168.1.1'

Which leads to an error. If I remove the remote ports, the policy gets enabled, but does not work Wouldn't that mean that all traffic from 22 from outside the WAN interface would be routed to my internal router? Might be naive but maybe I got that a little wrong.

Policy looks good. What errors are you getting?

Also check the following:

  • Go to System > Administration.
  • Under "SSH Access", set "Interface" to "unspecified" for "Dropbear instance" so it will listen on all interfaces.
  • Go to Network > Firewall > Traffic Rules and set up port forwarding for port 22 from WAN > LAN.

If you do this, it's recommended you configure ssh to use public / private keys instead of a user / password combo.