Patience, young anav! Sob gotta eat. And work, annoying prerequisite.
About this thing with addresses, the basic idea is that public addresses are good, because they allow to host servers and such, which is fun. Ideally, everyone should have enough public addresses, but until IPv6 takes over, it's currently problematic. So let's assume that you want nice static public IPv4 address, but your ISP gives you only some not good enough (dynamic, NAT 1:1), or none at all. But you may be able to find better one elsewhere (rent a VPS, ...). Then you can choose the simple and lazy way, make a VPN with private addresses and only do dstnat from that public address to internal one behind VPN. But where's the fun in that? If you got nice shiny public address, you want it on your router (or directly on internal server).
WG part of this is nothing special. Downright boring, really. On VPS/server, if it's RouterOS:
/interface wireguard
add name=WG listen-port=<server port> ...
/interface wireguard peers
add interface=WG allowed-address=<public address>/32 ...
/ip route
add dst-address=<public address> gateway=WG
On client:
/interface wireguard
add name=WG-WAN ...
/interface wireguard peers
add interface=WG-WAN allowed-address=0.0.0.0/0 endpoint-address=<server address> endpoint-port=<server port> ...
/ip address
add interface=WG-WAN address=<public address>/32
plus the usual dual-WAN config, because WG-WAN is same as another regular WAN interface. I told you it's boring.
The more interesting part is what you do on server side. Did you notice <public address> and <server address> in previous example? Yes, it's two addresses, one used by server and the other for you. There are different ways how to get it. It can be routed to server by ISP. So server has <server address> and ISP does:
/ip route
add dst-address=<public address> gateway=<server address>
which means that any traffic to <public address> is routed to <server address> and server can do anything it wants with it (route it further as in example). It's the "floating IP" from this thread.
Another way is that both addresses are from same subnet and what ISP meant is to assign them both to connected device. If it's RouterOS, it would be:
/ip address
add interface=WAN address=<server address>/<mask>
add interface=WAN address=<public address>/<mask>
But no, you want the second address on the other router! No problem, don't add <public address> as address, instead use proxy ARP to lie to ISP that it's there:
/ip arp
add interface=WAN address=<public address> published=yes
Done. Now everything to <public address> will be sent to your VPS/server/router and you can route it further via VPN to second one.
But it's not good. You need one address, but you had to get two. And you know that they'll charge extra for it. If only you could do it with one, you don't want address on server (VPS), you want it on your router (client). But you must have public address on VPS, otherwise you wouldn't be able to connect to it. And you can't have same address in two places, right? Wrong, of course you can (for recent v7; would be different for older versions, plus v6 couldn't use WG):
/ip address
add interface=WAN address=<shared public address>/<mask>
/interface wireguard
add name=WG listen-port=<server port> ...
/interface wireguard peers
add interface=WG allowed-address=<shared public address>/32 ...
/routing table
add name=to-client fib
/ip route
add dst-address=<shared public address> gateway=WG routing-table=to-client
/ip firewall mangle
add chain=prerouting dst-address=<shared public address> connection-state=new protocol=udp dst-port=<server port> action=accept
add chain=prerouting dst-address=<shared public address> connection-state=new action=mark-connection new-connection-mark=forward_conn passthrough=yes
add chain=prerouting connection-mark=forward_conn in-interface=WAN action=mark-routing new-routing-mark=to-client
So any connection to <shared public address>:<server port> (WG server) will be just accepted and will go to this device. But any other connection to <shared public address> will be marked and routed to second router (WG client). Hooray, success! Well, almost, I forgot that second router connecting to remote <shared public address> when it has same "own" local <shared public address> won't work well, or more precisely not at all. If it has RouterOS, it's probably doable, but I'll have to test it... later, because now I'm almost asleep.
--
Edit: About this last part with single shared address, it seems that I went too far. It's not impossible. But with UDP-based roaming-happy WG it's real PITA. Basic idea sort of works. Connection to WG server (<shared public address>:<server port>) is forced to use separate routing table with gateway being local ISP:
/interface wireguard
add name=wg-wan ...
/routing table
add name=to-server fib
add name=wg fib
/interface wireguard peers
add interface=wg-wan allowed-address=0.0.0.0/0 endpoint-address=<shared public address> endpoint-port=<server port> persistent-keepalive=10s public-key="xxx"
/ip address
add address=<shared public address> interface=wg-wan
/ip firewall mangle
add chain=output dst-address=<shared public address> protocol=udp dst-port=<server port> action=mark-routing new-routing-mark=to-server passthrough=no
add chain=prerouting in-interface=wg-wan connection-state=new action=mark-connection new-connection-mark=wg_conn passthrough=no
add chain=output connection-mark=wg_conn action=mark-routing new-routing-mark=wg passthrough=no
add chain=prerouting in-interface=!wg-wan connection-mark=wg_conn action=mark-routing new-routing-mark=wg passthrough=no
/ip route
add dst-address=<shared public address>/32 gateway=<local gateway> routing-table=to-server
add dst-address=0.0.0.0/0 gateway=wg-wan routing-table=wg
It works for initial packet that chooses local address as source. But then it realizes that best source for connecting to <shared public address> is actually <shared public address> and switches to that. So it needs some srcnat to fix it:
/ip firewall nat
add chain=srcnat dst-address=<shared public address> protocol=udp dst-port=<server port> action=masquerade
But then it still goes wrong, addresses and ports get somehow mixed up. And honestly, I lost my patience. It would work with something based on TCP, or if WG could be forced to bind to specified local address.