@@ 0,0 1,196 @@
+---
+title: 'No IP? No Problem!'
+taxonomy:
+ category:
+ - programming
+ tag:
+ - linux
+ - networking
+feed:
+ limit: 10
+page-toc:
+ active: true
+highlight: true
+publish_date: '2024-10-29 18:40'
+date: '2024-10-29 18:40'
+staticmath:
+ active: false
+twig_first: true
+visible: false
+sitemap: {}
+metadata:
+ description: 'How to get a free public IPv4 address'
+ keywords: linux, networking, public, ip, ipv4, rathole, cloudflare, tunnel
+---
+
+This is meant as a tutorial on how to use a VPS to get a public IPv4 address for self-hosting reasons. Often, people want to run a server out of their college dorm that doesn't give them a public IPv4 address, or out of their house from behind [CGNAT](https://en.wikipedia.org/wiki/Carrier-grade_NAT).
+
+It's a simple solution and an excellent alternative to software like [Rathole](https://github.com/rapiz1/rathole) or [Cloudflare Tunnel](https://www.cloudflare.com/products/tunnel) because this solution will properly pass the correct connecting IP addresses through, transparently. If you look at your webserver access logs while using software like Rathole or Cloudflare Tunnel, all the connections are arriving from `127.0.0.1`, and not from the real client address.
+
+===
+
+As a quick introduction, we will create a Wireguard connection between the server without an IP address and a virtual machine in the cloud. Only incoming traffic will go through the cloud VM. All outbound traffic will continue as normal. This means that there will be no latency for normal outbound internet use. The latency will only appear when someone accesses your website.
+
+## Step 1: Acquire a VPS with a Public IPv4 Address
+
+This is not an endorsement, but Oracle Cloud and Google Cloud both have generous free tiers and will give you a static IPv4 address with one virtual machine. Pick a region that is geographically close to where your server is. The specs of the VM are not important—this is extremely lightweight. The most important component is bandwidth, as the bandwidth of this machine will become the bandwidth of the incoming connections. This VPS must be running a modern Linux distribution.
+
+## Step 2: Install Required Software
+
+Verify that you have `nftables` installed on the VPS by running `nft --version`. If it is not installed, do so. Occasionally the `nft` command is kept in `/usr/sbin`, and may not be in the path of a non-root user. Additionally, some distributions may come with alternative firewall software, such as `firewalld` or `ufw`. Please ensure those are uninstalled.
+
+Install Wireguard on both machines. For Debian-based distributions, this will look like `sudo apt install wireguard`, and for Fedora-based distributions `sudo dnf install wireguard-tools`.
+
+## Step 3: Set Up Firewall
+
+On the cloud provider, open the port `51820/UDP` in the cloud firewall. Instructions vary by provider.
+
+Then, on the cloud virtual machine, create the file `/etc/nftables/proxy.nft`:
+
+```
+table ip nat {
+ chain PREROUTING {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp tcp dport 80 dnat to 192.168.77.2:80
+ meta l4proto tcp tcp dport 443 dnat to 192.168.77.2:443
+ }
+
+ chain INPUT {
+ type nat hook input priority 100; policy accept;
+ }
+
+ chain POSTROUTING {
+ type nat hook postrouting priority srcnat; policy accept;
+ }
+
+ chain OUTPUT {
+ type nat hook output priority -100; policy accept;
+ }
+}
+```
+
+Also create the file `/etc/nftables/main.nft`:
+
+```
+# Sample configuration for nftables service.
+# Load this by calling 'nft -f /etc/nftables/main.nft'.
+
+# Note about base chain priorities:
+# The priority values used in these sample configs are
+# offset by 20 in order to avoid ambiguity when firewalld
+# is also running which uses an offset of 10. This means
+# that packets will traverse firewalld first and if not
+# dropped/rejected there will hit the chains defined here.
+# Chains created by iptables, ebtables and arptables tools
+# do not use an offset, so those chains are traversed first
+# in any case.
+
+# drop any existing nftables ruleset
+flush ruleset
+
+# a common table for both IPv4 and IPv6
+table inet nftables_svc {
+
+ # protocols to allow
+ set allowed_protocols {
+ type inet_proto
+ elements = { icmp, icmpv6 }
+ }
+
+ # interfaces to accept any traffic on
+ set allowed_interfaces {
+ type ifname
+ elements = { "lo" }
+ }
+
+ # services to allow
+ set allowed_tcp_dports {
+ type inet_service
+ elements = { ssh, http, https, 51820 }
+ }
+
+ # services to allow
+ set allowed_udp_dports {
+ type inet_service
+ elements = { 51820 }
+ }
+
+ # this chain gathers all accept conditions
+ chain allow {
+ ct state established,related accept
+
+ meta l4proto @allowed_protocols accept
+ iifname @allowed_interfaces accept
+ tcp dport @allowed_tcp_dports accept
+ udp dport @allowed_udp_dports accept
+ }
+
+ # base-chain for traffic to this host
+ chain INPUT {
+ type filter hook input priority filter + 20
+ policy accept
+
+ jump allow
+ reject with icmpx type port-unreachable
+ }
+}
+
+include "/etc/nftables/proxy.nft"
+```
+
+This firewall rule will NOT close SSH access. If you have publicly available SSH, that is a bad idea, and you should adjust `allowed_tcp_dports` to not include SSH. This default configuration will only pass through HTTP and HTTPS. Adjust `allowed_tcp_dports` to allow your TCP port, and `allowed_udp_dports` to allow your UDP port. In the first file, use the example HTTP/HTTPS configuration to forward another port. Keep in mind that this port forwarding will take priority! If you have SSH open to the VPS and you try forwarding SSH, you WILL lose SSH access!
+
+## Step 4: Set Up Wireguard
+
+First, set up the Wireguard keys. On the cloud VM, run this command as root:
+
+```
+wg genkey | tee privatekey | wg pubkey > publickey
+```
+
+Keep these generated files (`privatekey`, `publickey`) in a safe place.
+
+Repeat this generation command on the other machine.
+
+First, create the file `/etc/wireguard/wg0.conf` on the cloud VM:
+
+```
+[Interface]
+Address = 192.168.77.1/24
+ListenPort = 51820
+PrivateKey = [FIRST_GENERATED_PRIVATE_KEY]
+
+[Peer]
+PublicKey = [THE_PUBLIC_KEY_GENERATED_ON_THE_OTHER_MACHINE]
+AllowedIPs = 192.168.77.2/32
+PersistentKeepalive = 30
+```
+
+Create the file `/etc/wireguard/wg0.conf` on the other machine:
+
+```
+[Interface]
+PrivateKey = [PRIVATE_KEY_GENERATED_ON_THIS_MACHINE]
+Address = 192.168.77.2/32
+
+Table = 123
+PreUp = ip rule add from 192.168.77.2 table 123 priority 456
+PostDown = ip rule del from 192.168.77.2 table 123 priority 456
+
+[Peer]
+PublicKey = [PUBLIC_KEY_GENERATED_ON_THE_OTHER_MACHINE]
+Endpoint = [IP_ADDRESS_OF_THE_CLOUD_VM]:51820
+AllowedIPs = 0.0.0.0/0
+PersistentKeepalive = 30
+```
+
+Then, reload the firewall rules and start the Wireguard tunnels:
+
+```
+sudo systemctl enable --now wg-quick@wg0.service
+sudo systemctl restart nftables.service
+```
+
+---
+
+That should be all you need to have a public static IPv4 address when self-hosting in an environment where you don't have any such address. If you have any questions, feel free to [contact me](/). Please try fixing your own problem before asking me for help, though. If you do ask me for help, please be as descriptive as possible and tell me the troubleshooting steps you've taken. I'll ignore the cry for help otherwise.