Sorry if I posted this in the wrong place. Let me know if I should move this to another SE site. On with the story...

My home ISP sometimes (but not consistently) forces us through a CGNAT, however I need remote access to the local devices in a reliable fashion (as long as there is Internet connectivity in the first place; no way to avoid this requirement :) ). Before switching ISPs (old ISP always gave me the same public IPv4 address) I could just use OpenVPN and be done with that.

Now that CGNAT is a real possibility OpenVPN is no longer a reliable way to connect to my LAN resources remotely. So I'm looking for another reliable enough solution (it will enable me several things that are both kinda required -- accessing security cameras remotely -- and useful -- reverse SSH server to my workplace).

Now for the setup:

  • At home, I have a Raspberry Pi. Model 3 B+ if it matters (I'd be surprised, but providing it for completeness). It's behind a router of my own which connects to the ISP (PPPoE). It has full access to LAN resources. I have a private, fixed IPv4 (though now with the CGNAT issue I contemplate removing the "fixed" requirement; it's probably not as useful as before to have it fixed anyway) and an automatic (SLAAC, no privacy extensions) publicly routed IPv6 address. No guarantees that I will get the same /64 from reconnect to reconnect (and thus IP addresses will vary with time).
  • Off-site, I have an AWS EC2 host (the smallest one, which is "free" but I think won't truly be free). I have elastic IPv4 and IPv6 configured on the host, with proper gateway configuration (wasted a lot of time but managed to do it in the end). So technically I could connect from here to the Pi via IPv6 (assuming there is a proper Dynamic DNS service the Pi can use for IPv6) or from Pi to the AWS host on both IPv4 and IPv6.
  • At work, I have a highly guarded network, for which I only want to do reverse SSH. I can probably just use the AWS instance as a jump host and resolve it very quickly. I mean, I can run the SSH server on the AWS instance on port 443 anyway. So it's no real issue (port 22 is blocked by work firewall :( )

What I need help with is twofold:

  1. First, how to set up the direct connection from my Raspberry Pi to the AWS host so that the AWS host has direct access to all my LAN resources (eventually customizable by my firewall rules on the Raspberry Pi)
  2. Second, how to ensure this support will automatically start every time the Pi is restarted (I tend to reboot it often enough, and power outages will cause unintended reboots as well).

Note that I do have a workaround but it genuinely sucks. It involves restarting my router through the TP-Link cloud service several times every time I get a CGNAT IP address until I get a public one. Then my ISP is helpful enough to provide a proper Dynamic DNS service so I can resolve to my public address (OR my private address, if I do get CGNAT; that's not that helpful though). I want to be able to forget about such workarounds, really.

  • (1) Perhaps request a static IPv6 prefix from the ISP for your devices, (2) Check if the ISP supports Port Control Protocol (PCP) for requesting a port-forward at the ISP level, (3) Use third-party remote-control provider that does the handshaking (example TeamViewer). – harrymc Aug 28 '20 at 17:31
  • You suggested something that works like TeamViewer. The thing is, I have an AWS host which I'm currently not even using for anything else other than a guaranteed-public-IP host (I don't care that it's a VM in reality -- it's got a static public IP address, it's got everything, and I want to use that host to gain access to my home network indifferent of my home ISP configuration) In the end all I really need is to just forward a port from that guaranteed-public-address to a non-guaranteed-public system. Even a single UDP port for OpenVPN suffices. – Paul Stelian Aug 29 '20 at 17:09
  • (Also my IP cameras don't support any customization -- they're made by some weird Chinese brand and their own external service is highly unreliable -- it's broken more often than working) – Paul Stelian Aug 29 '20 at 17:12
  • TeamViewer and similar don't need any public IP, as the connection is made via a known third-party server which then takes no more part in the exchange. As connection is by server ID, and you can set this ID to static, re-connection is easy. – harrymc Aug 29 '20 at 18:14
  • @harrymc Yeah but Teamviewer isn't doing what I need to do -- port forwarding to LAN resources. Hence my question. You're starting to get off-topic honestly -- I want something to port forward, you suggest me Teamviewer which doesn't do nearly everything I need this solution to do. – Paul Stelian Aug 30 '20 at 15:19

I have actually figured it out myself in the end. I followed the usual tutorials:

  • First, install OpenVPN on both the server (EC2 instance) and the client (Raspberry Pi behind the CGNAT), and also install Easy-RSA on the server only.
  • Then, generate a few things using Easy-RSA (info taken straight from tutorials on the OpenVPN community pages):
    • First of all, configure the variables in the file "vars". The defaults work well but it's recommended to change them anyway.
    • Copy openssl-1.0.0.cnf to openssl.cnf (other versions might also work).
    • Run ./clean-all (this will erase any preexisting keys and extra configuration, so as to start from a blank slate).
    • Run ./build-ca (this will generate keys/ca.crt and keys/ca.key; the latter must be protected -- you can shred it once you're sure you don't need to update the configuration to add more clients. The former is the certificate which must remain)
    • Run ./build-key-server to generate a server key pair. Only the server requires this.
    • Run ./build-key to generate the keys for clients. Run it once per client. I only ran it once in total, for my client "raspberrypi". The files generated will need to be copied on the client side.
    • Copy files to where they belong:
      • keys/ca.crt is needed by both server and client.
      • keys/ca.key is needed if you want to add additional clients and is the main thing you want to protect. If you don't need the extra flexibility, it is recommended you run the "shred" command on it or move it to a known-secure system (which could be air-gapped for what it's worth)
      • keys/raspberrypi.{crt,key} belong to the client (in my case, the client is raspberrypi, you type your own specific name for the client(s) ) and should be copied accordingly to the clients.
      • keys/server.{crt,key} remain on server. The .crt file is automatically sent over on any connection attempt though so no need to copy it on the client manually.
    • Easy-RSA part is now done.
  • Set up OpenVPN on server side
    • The default server configuration is fine, save for a few changes:
      • The ca, cert and key options must be updated to point to the ca.crt, server.crt and, respectively, server.key files. The server.key file should be protected (0400 permissions), although I'm not sure if this is actually checked.
      • I have set "topology subnet". This isn't strictly necessary but is a good thing.
      • I have changed the "server" directive to another private IPv4 range, to ensure I don't conflict with another OpenVPN server (the one from my router). After all I'll do some static routing later so the ranges must not overlap.
      • client-config-dir client (set the "client" subfolder to be special and contain client-specific configurations; this is important for the routing)
      • client-to-client I keep on, again so that routing works properly.
      • I have commented-out the "tls-auth ta.key 0" option in both cases; this does generate a warning but I don't need the extra security. I might uncomment it in the future once I figure out how it works. For security it is however extremely recommended to have this option.
      • I have added a statement push "route" to push the route to the private network of the AWS towards my Raspberry Pi.
    • Additionally, for the client you need to have a file client/raspberrypi (again based on the client name) which contains iroute (so that routing works from the AWS instance towards the Pi and the home network.
  • The client needs to be set up as well
    • Set up the remote address. I just put the elastic IP address I have on my AWS instance, because it ain't changing until I mess with it.
    • Setup the ca, cert, key (ca to ca.crt, cert to raspberrypi.crt, key to raspberrypi.key) directives.
    • Comment out the tls-auth directive, just like on server. This must match the server.
  • Enable SystemD services (this takes care of enabling the tunnel at boot). On server, you do systemctl enable openvpn@server; systemctl start openvpn@server assuming your configuration file is /etc/openvpn/server.conf. You cannot use this for subfolders. On client it's the same except since it's client.conf for the filename you put openvpn@client.

Now what's left for me is doing a few port forwards, which are however not the subject of this question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.