Bug: Web Panel reassigns IP addresses already in use by natively-created AmneziaWG clients.
Environment
- Panel image:
prvtpro/amnezia-panel:1.5.0
- Protocol: AWG2 (AmneziaWG)
- Server was originally configured through the official app AmneziaVPN, Web Panel was installed afterward on top of the existing deployment
Summary
All clients were created directly through the native AmneziaVPN app before the panel was installed, so they never got an entry in the panel's own client tracking. After installing the panel and creating new clients through it, the panel repeatedly assigned IP addresses that were already in use by these pre-existing peers. This caused the existing peer to lose its AllowedIPs on the live WireGuard interface, effectively disconnecting a real, actively-used device without warning.
This happened multiple times across different new-client-creation attempts, colliding with a different pre-existing client each time.
Root cause
In managers/awg_manager.py, _get_next_ip takes the last IP found by file line order and simply increments the last octet by 1 — it doesn't check whether the resulting IP is already assigned to another peer.
Problematic code
def _get_next_ip(self, protocol_type):
"""Calculate the next available IP for a new client."""
used_ips = self._get_used_ips(protocol_type)
if not used_ips:
base = self._get_subnet_base(protocol_type)
parts = base.split('.')
parts[3] = '2'
return '.'.join(parts)
# Get the last used IP and increment
last_ip = used_ips[-1]
parts = last_ip.split('.')
last_octet = int(parts[3])
if last_octet == 254:
next_octet = last_octet + 3
elif last_octet == 255:
next_octet = last_octet + 2
else:
next_octet = last_octet + 1
parts[3] = str(next_octet)
return '.'.join(parts)
If the last [Peer] block in the config file (by line order — which changes any time a peer is added/removed) has a lower octet than peers listed earlier, this returns an IP that's already taken.
Workaround I used
Patched the function to scan all occupied octets in the subnet and pick the lowest genuinely free one, instead of trusting file-line order. After this change, new clients get valid, genuinely free IPs with no further collisions.
Fix
def _get_next_ip(self, protocol_type):
"""Calculate the next available IP for a new client."""
used_ips = self._get_used_ips(protocol_type)
base = self._get_subnet_base(protocol_type)
base_parts = base.split('.')
if not used_ips:
base_parts[3] = '2'
return '.'.join(base_parts)
used_octets = set()
for ip in used_ips:
parts = ip.split('.')
if parts[0:3] == base_parts[0:3]:
used_octets.add(int(parts[3]))
next_octet = 2
while next_octet in used_octets and next_octet < 254:
next_octet += 1
base_parts[3] = str(next_octet)
return '.'.join(base_parts)
Ran into this issue and tried to fix it — not sure if it's the right approach, but wanted to share in case it helps. If the maintainer gets a chance to weigh in on whether this is the correct way to handle it, that could help others hitting the same problem.
Bug: Web Panel reassigns IP addresses already in use by natively-created AmneziaWG clients.
Environment
prvtpro/amnezia-panel:1.5.0Summary
All clients were created directly through the native AmneziaVPN app before the panel was installed, so they never got an entry in the panel's own client tracking. After installing the panel and creating new clients through it, the panel repeatedly assigned IP addresses that were already in use by these pre-existing peers. This caused the existing peer to lose its
AllowedIPson the live WireGuard interface, effectively disconnecting a real, actively-used device without warning.This happened multiple times across different new-client-creation attempts, colliding with a different pre-existing client each time.
Root cause
In
managers/awg_manager.py,_get_next_iptakes the last IP found by file line order and simply increments the last octet by 1 — it doesn't check whether the resulting IP is already assigned to another peer.Problematic code
If the last
[Peer]block in the config file (by line order — which changes any time a peer is added/removed) has a lower octet than peers listed earlier, this returns an IP that's already taken.Workaround I used
Patched the function to scan all occupied octets in the subnet and pick the lowest genuinely free one, instead of trusting file-line order. After this change, new clients get valid, genuinely free IPs with no further collisions.
Fix
Ran into this issue and tried to fix it — not sure if it's the right approach, but wanted to share in case it helps. If the maintainer gets a chance to weigh in on whether this is the correct way to handle it, that could help others hitting the same problem.