Xray with AmneziaVPN - can't access internet

This won’t work, because dnat-dns chain will be automatically overwritten on network interface up/down, that’s why it doesn’t work for you.
You need to create a separate nat chain as stated in the linked guide.

I did this too, doesn’t work

What’s the output of this command with these rules?

sudo nft list ruleset

Did you try DNS resolution in qubes connected to sys-vpn with these rules?

Here’s what I have with these rules:

table ip qubes {
	set downstream {
		type ipv4_addr
	}

	set allowed {
		type ifname . ipv4_addr
	}

	chain prerouting {
		type filter hook prerouting priority raw; policy accept;
		iifgroup 2 goto antispoof
		ip saddr @downstream counter packets 0 bytes 0 drop
	}

	chain antispoof {
		iifname . ip saddr @allowed accept
		counter packets 0 bytes 0 drop
	}

	chain postrouting {
		type nat hook postrouting priority srcnat; policy accept;
		oifgroup 2 accept
		oif "lo" accept
		masquerade
	}

	chain input {
		type filter hook input priority filter; policy drop;
		jump custom-input
		ct state invalid counter packets 0 bytes 0 drop
		iifgroup 2 udp dport 68 counter packets 0 bytes 0 drop
		ct state established,related accept
		iifgroup 2 meta l4proto icmp accept
		iif "lo" accept
		iifgroup 2 counter packets 0 bytes 0 reject with icmp host-prohibited
		counter packets 0 bytes 0
	}

	chain forward {
		type filter hook forward priority filter; policy accept;
		jump custom-forward
		ct state invalid counter packets 0 bytes 0 drop
		ct state established,related accept
		oifgroup 2 counter packets 0 bytes 0 drop
	}

	chain custom-input {
	}

	chain custom-forward {
	}

	chain nat {
		type nat hook prerouting priority dstnat; policy accept;
		iifname "vif*" tcp dport 53 dnat to 9.9.9.9
		iifname "vif*" udp dport 53 dnat to 9.9.9.9
	}

	chain dnat-dns {
		type nat hook prerouting priority dstnat; policy accept;
		ip daddr 10.139.1.1 udp dport 53 dnat to 10.139.1.1
		ip daddr 10.139.1.1 tcp dport 53 dnat to 10.139.1.1
		ip daddr 10.139.1.2 udp dport 53 dnat to 10.139.1.2
		ip daddr 10.139.1.2 tcp dport 53 dnat to 10.139.1.2
	}
}
table ip6 qubes {
	set downstream {
		type ipv6_addr
	}

	set allowed {
		type ifname . ipv6_addr
	}

	chain antispoof {
		iifname . ip6 saddr @allowed accept
		counter packets 0 bytes 0 drop
	}

	chain prerouting {
		type filter hook prerouting priority raw; policy accept;
		iifgroup 2 goto antispoof
		ip6 saddr @downstream counter packets 0 bytes 0 drop
	}

	chain postrouting {
		type nat hook postrouting priority srcnat; policy accept;
		oifgroup 2 accept
		oif "lo" accept
		masquerade
	}

	chain _icmpv6 {
		meta l4proto != ipv6-icmp counter packets 0 bytes 0 reject with icmpv6 admin-prohibited
		icmpv6 type { nd-router-advert, nd-redirect } counter packets 0 bytes 0 drop
		accept
	}

	chain input {
		type filter hook input priority filter; policy drop;
		jump custom-input
		ct state invalid counter packets 0 bytes 0 drop
		ct state established,related accept
		iifgroup 2 goto _icmpv6
		iif "lo" accept
		ip6 saddr fe80::/64 ip6 daddr fe80::/64 udp dport 546 accept
		meta l4proto ipv6-icmp accept
		counter packets 0 bytes 0
	}

	chain forward {
		type filter hook forward priority filter; policy accept;
		jump custom-forward
		ct state invalid counter packets 0 bytes 0 drop
		ct state established,related accept
		oifgroup 2 counter packets 0 bytes 0 drop
	}

	chain custom-input {
	}

	chain custom-forward {
	}
}
table ip qubes-firewall {
	chain forward {
		type filter hook forward priority filter; policy drop;
		ct state established,related accept
		iifname != "vif*" accept
	}

	chain prerouting {
		type filter hook prerouting priority raw; policy accept;
		iifname != "vif*" ip saddr 10.137.0.15 drop
	}

	chain postrouting {
		type filter hook postrouting priority raw; policy accept;
		oifname != "vif*" ip daddr 10.137.0.15 drop
	}
}
table ip6 qubes-firewall {
	chain forward {
		type filter hook forward priority filter; policy drop;
		ct state established,related accept
		iifname != "vif*" accept
	}

	chain prerouting {
		type filter hook prerouting priority raw; policy accept;
	}

	chain postrouting {
		type filter hook postrouting priority raw; policy accept;
	}
}
# Warning: table ip filter is managed by iptables-nft, do not touch!
table ip filter {
	chain amnvpn.anchors {
		counter packets 4 bytes 184 jump amnvpn.a.000.allowLoopback
		counter packets 4 bytes 184 jump amnvpn.a.320.allowDNS
		counter packets 4 bytes 184 jump amnvpn.a.310.blockDNS
		counter packets 4 bytes 184 jump amnvpn.a.300.allowLAN
		counter packets 4 bytes 184 jump amnvpn.a.290.allowDHCP
		counter packets 4 bytes 184 jump amnvpn.a.200.allowVPN
		counter packets 4 bytes 184 jump amnvpn.a.120.blockNets
		counter packets 4 bytes 184 jump amnvpn.a.110.allowNets
		counter packets 4 bytes 184 jump amnvpn.a.100.blockAll
	}

	chain amnvpn.a.000.allowLoopback {
		counter packets 0 bytes 0 jump amnvpn.000.allowLoopback
	}

	chain amnvpn.000.allowLoopback {
		oifname "lo*" counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.320.allowDNS {
		counter packets 0 bytes 0 jump amnvpn.320.allowDNS
	}

	chain amnvpn.320.allowDNS {
		oifname "amn0*" ip daddr 1.1.1.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 1.1.1.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 1.1.1.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 1.1.1.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 1.1.1.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 1.1.1.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 1.0.0.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 1.0.0.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 1.0.0.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 1.0.0.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 1.0.0.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 1.0.0.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 127.0.0.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 127.0.0.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 127.0.0.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 127.0.0.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 127.0.0.1 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 127.0.0.1 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 127.0.0.53 udp dport 53 counter packets 0 bytes 0 accept
		oifname "amn0*" ip daddr 127.0.0.53 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 127.0.0.53 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun0*" ip daddr 127.0.0.53 tcp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 127.0.0.53 udp dport 53 counter packets 0 bytes 0 accept
		oifname "tun2*" ip daddr 127.0.0.53 tcp dport 53 counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.310.blockDNS {
		counter packets 0 bytes 0 jump amnvpn.310.blockDNS
	}

	chain amnvpn.310.blockDNS {
		udp dport 53 counter packets 0 bytes 0 reject
		tcp dport 53 counter packets 0 bytes 0 reject
	}

	chain amnvpn.a.300.allowLAN {
		counter packets 0 bytes 0 jump amnvpn.300.allowLAN
	}

	chain amnvpn.300.allowLAN {
		ip daddr 10.0.0.0/8 counter packets 0 bytes 0 accept
		ip daddr 169.254.0.0/16 counter packets 0 bytes 0 accept
		ip daddr 172.16.0.0/12 counter packets 0 bytes 0 accept
		ip daddr 192.168.0.0/16 counter packets 0 bytes 0 accept
		ip daddr 224.0.0.0/4 counter packets 0 bytes 0 accept
		ip daddr 255.255.255.255 counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.290.allowDHCP {
		counter packets 0 bytes 0 jump amnvpn.290.allowDHCP
	}

	chain amnvpn.290.allowDHCP {
		ip daddr 255.255.255.255 udp sport 68 udp dport 67 counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.200.allowVPN {
		counter packets 0 bytes 0 jump amnvpn.200.allowVPN
	}

	chain amnvpn.200.allowVPN {
		oifname "amn0*" counter packets 0 bytes 0 accept
		oifname "tun0*" counter packets 0 bytes 0 accept
		oifname "tun2*" counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.120.blockNets {
		counter packets 0 bytes 0 jump amnvpn.120.blockNets
	}

	chain amnvpn.120.blockNets {
	}

	chain amnvpn.a.110.allowNets {
		counter packets 0 bytes 0 jump amnvpn.110.allowNets
	}

	chain amnvpn.110.allowNets {
		ip daddr [VPN's IP] counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.100.blockAll {
		counter packets 0 bytes 0 jump amnvpn.100.blockAll
	}

	chain amnvpn.100.blockAll {
		counter packets 0 bytes 0 reject
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		counter packets 4 bytes 184 jump amnvpn.anchors
	}
}
# Warning: table ip6 filter is managed by iptables-nft, do not touch!
table ip6 filter {
	chain amnvpn.anchors {
		counter packets 9 bytes 576 jump amnvpn.a.000.allowLoopback
		counter packets 9 bytes 576 jump amnvpn.a.310.blockDNS
		counter packets 9 bytes 576 jump amnvpn.a.300.allowLAN
		counter packets 8 bytes 520 jump amnvpn.a.290.allowDHCP
		counter packets 8 bytes 520 jump amnvpn.a.250.blockIPv6
		counter packets 8 bytes 520 jump amnvpn.a.200.allowVPN
		counter packets 8 bytes 520 jump amnvpn.a.100.blockAll
	}

	chain amnvpn.a.000.allowLoopback {
		counter packets 1 bytes 56 jump amnvpn.000.allowLoopback
	}

	chain amnvpn.000.allowLoopback {
		oifname "lo*" counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.310.blockDNS {
	}

	chain amnvpn.310.blockDNS {
		udp dport 53 counter packets 0 bytes 0 reject
		tcp dport 53 counter packets 0 bytes 0 reject
	}

	chain amnvpn.a.300.allowLAN {
		counter packets 1 bytes 56 jump amnvpn.300.allowLAN
	}

	chain amnvpn.300.allowLAN {
		ip6 daddr fc00::/7 counter packets 0 bytes 0 accept
		ip6 daddr fe80::/10 counter packets 0 bytes 0 accept
		ip6 daddr ff00::/8 counter packets 1 bytes 56 accept
	}

	chain amnvpn.a.290.allowDHCP {
		counter packets 0 bytes 0 jump amnvpn.290.allowDHCP
	}

	chain amnvpn.290.allowDHCP {
		ip6 daddr ff00::/8 udp sport 546 udp dport 547 counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.250.blockIPv6 {
		counter packets 0 bytes 0 jump amnvpn.250.blockIPv6
	}

	chain amnvpn.250.blockIPv6 {
		oifname != "lo*" counter packets 0 bytes 0 reject
	}

	chain amnvpn.a.200.allowVPN {
	}

	chain amnvpn.200.allowVPN {
		oifname "amn0*" counter packets 0 bytes 0 accept
		oifname "tun0*" counter packets 0 bytes 0 accept
		oifname "tun2*" counter packets 0 bytes 0 accept
	}

	chain amnvpn.a.100.blockAll {
		counter packets 0 bytes 0 jump amnvpn.100.blockAll
	}

	chain amnvpn.100.blockAll {
		counter packets 0 bytes 0 reject
	}

	chain OUTPUT {
		type filter hook output priority filter; policy accept;
		counter packets 9 bytes 576 jump amnvpn.anchors
	}
}
table ip raw {
	chain amnvpn.anchors {
		counter packets 4 bytes 184 jump amnvpn.a.100.vpnTunOnly
	}

	chain amnvpn.a.100.vpnTunOnly {
	}

	chain amnvpn.100.vpnTunOnly {
		counter packets 0 bytes 0 accept
	}

	chain PREROUTING {
		type filter hook prerouting priority raw; policy accept;
		counter packets 4 bytes 184 jump amnvpn.anchors
	}
}
table ip6 raw {
	chain amnvpn.anchors {
		counter packets 6 bytes 396 jump amnvpn.a.100.vpnTunOnly
	}

	chain amnvpn.a.100.vpnTunOnly {
	}

	chain amnvpn.100.vpnTunOnly {
		counter packets 0 bytes 0 accept
	}

	chain PREROUTING {
		type filter hook prerouting priority raw; policy accept;
		counter packets 6 bytes 396 jump amnvpn.anchors
	}
}
# Warning: table ip nat is managed by iptables-nft, do not touch!
table ip nat {
	chain amnvpn.anchors {
		counter packets 2 bytes 104 jump amnvpn.a.100.transIp
	}

	chain amnvpn.a.100.transIp {
	}

	chain amnvpn.100.transIp {
		counter packets 0 bytes 0 masquerade
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		counter packets 2 bytes 104 jump amnvpn.anchors
	}
}
# Warning: table ip6 nat is managed by iptables-nft, do not touch!
table ip6 nat {
	chain amnvpn.anchors {
		counter packets 2 bytes 144 jump amnvpn.a.100.transIp
	}

	chain amnvpn.a.100.transIp {
	}

	chain amnvpn.100.transIp {
		counter packets 0 bytes 0 XT target MASQUERADE not found

	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		counter packets 2 bytes 144 jump amnvpn.anchors
	}
}
# Warning: table ip mangle is managed by iptables-nft, do not touch!
table ip mangle {
	chain amnvpn.anchors {
		counter packets 4 bytes 184 jump amnvpn.a.100.tagPkts
	}

	chain amnvpn.a.100.tagPkts {
	}

	chain amnvpn.100.tagPkts {
		meta cgroup 1383 counter packets 0 bytes 0 meta mark set 0x3211
	}

	chain OUTPUT {
		type route hook output priority mangle; policy accept;
		counter packets 4 bytes 184 jump amnvpn.anchors
	}
}
# Warning: table ip6 mangle is managed by iptables-nft, do not touch!
table ip6 mangle {
	chain amnvpn.anchors {
		counter packets 9 bytes 576 jump amnvpn.a.100.tagPkts
	}

	chain amnvpn.a.100.tagPkts {
	}

	chain amnvpn.100.tagPkts {
		meta cgroup 1383 counter packets 0 bytes 0 meta mark set 0x3211
	}

	chain OUTPUT {
		type route hook output priority mangle; policy accept;
		counter packets 9 bytes 576 jump amnvpn.anchors
	}
}

I just tried DNS resolution in both sys-vpn and connected qubes. None of them works.

Maybe these DNS rules from AmneziaVPN are causing this issue.
Do you see the packet counter increasing in these rules when you try to resolve some DNS in the qube connected to sys-vpn?

I guess you can try to install systemd-resolved in the template of sys-vpn qube:

Maybe this will fix the issue.

Or you can use 1.1.1.1 or 1.0.0.1 DNS instead of 9.9.9.9 that is allowed by AmneziaVPN rules.

using 1.1.1.1 or 1.0.0.1 DNS instead of 9.9.9.9 seems not to help.

Here’s what I have when I’m trying to start systemd-resolved:

user@sys-vpn-2:~$ sudo systemctl start systemd-resolved
Failed to start systemd-resolved.service: Unit systemd-resolved.service not found.

Do you see the packet counter increasing in the amnvpn.a.310.blockDNS / amnvpn.310.blockDNS chains when you try to resolve some DNS in the qube connected to sys-vpn?
I guess these rules that allow 1.1.1.1 and 1.0.0.1 are generated when you add these DNS servers in /etc/resolve.conf manually and start the AmneziaVPN, that’s why it didn’t work for you now when you didn’t add these servers manually.

You need to install the systemd-resolved package in the template of your sys-vpn qube.

No, I don’t see that.

So, what have worked - you were right. If I write 1.1.1.1 and 1.0.0.1 to /etc/resolv.conf manually and then start amnezia, dns resolution works until the reload of the qube or I guess network up\down.

I’m using a standaloneVM as sys-vpn qube, I’m not sure if installing systemd-resolved to the template would work, but I don’t know much about differences in qube types yet.

As I understand the 1st solution that I have now is install systemd-resolved, which should give an ability to Amnezia to use its own DNS (there’s an option in the app to toggle using DNS that will be instaleld onto my VPS)?

And the 2nd one is to override resolv.conf on qube’s start in rc.local. (I’m not sure what these things are doing that you suggested here: Xray with AmneziaVPN - can't access internet - #14 by klamantikuspl But I will leave it as you suggest, as you definitely understand much more than me).

It seems that 1st one is easier in terms of maintaining, as I’ll be able to manage it in the Amnezia’s app. But I’m not sure which type of qube I need to use. So, until I’m waiting for you advice, I will try to create new template for vpn qube (installing systemd-resolved) and create an AppVM, and if it won’t work, I’ll try a few other configurations.

Thank you for your support and efforts, means a lot!

Yes, it works! As it’s standaloneVM, I’ve installed systemd-resolved directly into it and now I finally have working VPN and I know why it works.

Now it’s time to discover which qube should I use: standalone on debian (as it’s more stable - that’s what gemini said :sweat_smile:) or appVM with a template where systemd-resolved will be installed.

I guess I should use standalone.

I heard about minimal templates, so they won’t take so much space, but I don’t know what’s that yet and where can I get it.