LXD using IPVLAN for public ip alias

So here’s my test setup:

lxc init ubuntu:18.04 cipvlan
lxc config device add cipvlan eth0 nic nictype=ipvlan ipv4.address=192.168.1.200 parent=enp3s0
lxc start cipvlan

Then inside container, modify netplan config to:

network:
    version: 2
    ethernets:
      eth0:
        addresses:
          - 192.168.1.200/32
        nameservers:
          addresses:
          - 8.8.8.8
        routes:
          - to: 0.0.0.0/0
            via: 169.254.0.1
            on-link: true
netplan apply

Check ping:

lxc exec cipvlan -- ping 8.8.8.8 -c 5
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=58 time=24.0 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=58 time=23.9 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=58 time=23.8 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=58 time=23.9 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=58 time=23.8 ms

--- 8.8.8.8 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 23.825/23.952/24.049/0.079 ms

Install nginx

lxc exec cipvlan -- apt install nginx
lxc exec cipvlan -- systemctl start nginx
lxc exec cipvlan -- netstat -tlpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      728/nginx: master p 
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      139/systemd-resolve 
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      199/sshd            
tcp6       0      0 :::80                   :::*                    LISTEN      728/nginx: master p 
tcp6       0      0 :::22                   :::*                    LISTEN      199/sshd 

Now, importantly, ipvlan does not allow the container and the host to communicate with each other, so checking that nginx is accessible from the host is not going to work.

Instead I go to a different PC on the host’s physical network and run:

curl -I http://192.168.1.200
 curl -I http://192.168.1.200
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Thu, 19 Mar 2020 09:53:29 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Thu, 19 Mar 2020 09:49:27 GMT
Connection: keep-alive
ETag: "5e734027-264"
Accept-Ranges: bytes

Good, its working.

Let’s see how that looked with tcpdump inside the container:

lxc exec cipvlan -- tcpdump -l -nn -i eth0 port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
09:54:33.770992 IP 192.168.1.200.80 > 192.168.1.2.54828: Flags [S.], seq 1839355293, ack 352489863, win 65160, options [mss 1460,sackOK,TS val 3790088148 ecr 3985982135,nop,wscale 7], length 0
09:54:33.771390 IP 192.168.1.200.80 > 192.168.1.2.54828: Flags [.], ack 79, win 509, options [nop,nop,TS val 3790088148 ecr 3985982136], length 0
09:54:33.771706 IP 192.168.1.200.80 > 192.168.1.2.54828: Flags [P.], seq 1:248, ack 79, win 509, options [nop,nop,TS val 3790088148 ecr 3985982136], length 247: HTTP: HTTP/1.1 200 OK
09:54:33.772404 IP 192.168.1.200.80 > 192.168.1.2.54828: Flags [F.], seq 248, ack 80, win 509, options [nop,nop,TS val 3790088149 ecr 3985982136], length 0

So we can see that tcpdump is working inside the container and can see the request arriving.

So I would suggest double checking that your host’s firewall doesn’t have any DNAT rules or anything else that could be blocking the request, also double check you don’t have any proxy devices added to your instances that could be interfering with inbound requests on port 80.