"routed" LXC containers with public IP in Vagrant

Hello guys, I’m pulling my hair out here, so I hope you can save them. I’m not very knowledgeable when it comes to linux networking, but I decided to learn it by setting up externally accessible LXC containers. Unfortunately I got stuck. My approach right now is pretty naive, so any help with at least basic explanations will be welcome.

What I try to achieve: Setup in Vagrant, that would make containers accessible by IPs, by my local machine. So Vagrant would be the LXC host.

Host OS (Vagrant): Ubuntu 20.04
Guest OS: Debian 10

My Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|

  config.vm.define "main" do |main|
    main.vm.box = "bento/ubuntu-20.04"
    main.vm.box_version = "202010.24.0"
    main.vm.hostname = "test-luken-tech.pl"

    main.vm.network "public_network", auto_config: false

    main.vm.provision "shell",
      run: "always",
      inline: "ip address add 192.168.7.200/24 dev eth1"
    main.vm.provision "shell",
      run: "always",
      inline: "ip address add 192.168.7.201/24 dev eth1"
    main.vm.provision "shell",
      run: "always",
      inline: "ip address add 192.168.7.202/24 dev eth1"
    main.vm.provision "shell",
      run: "always",
      inline: "ip link set eth1 up"

    main.vm.provider :virtualbox do |vb|
        vb.memory = 1024
    end
    main.vm.network :forwarded_port, guest: 993, host: 9930
    main.vm.network :forwarded_port, guest: 587, host: 5870
  end

end

There is some irrelevant stuff, like port forwarding, that can be ignored, I just put it as is.
NOTE: My local network with the gateway to the internet is: 192.168.7.0

LXC version: 4.0.4

Now, my lxd configuration I’m loading with lxd init is:

config:
  core.https_address: '[::]:8443'
  core.trust_password: true
networks: []
storage_pools:
- config:
    source: /home/luken/lxd-storage-pools
  description: ""
  name: default
  driver: dir
profiles:
- name: default
  config: {}
  description: ""
  devices:
    root:
      path: /
      pool: default
      type: disk
- name: mail-server
  config:
    user.network-config: |
      version: 2
      ethernets:
        eth0:
          addresses:
          - 192.168.7.201/32
          nameservers:
            addresses:
            - 8.8.8.8
          routes:
          - to: 0.0.0.0/0
            via: 169.254.0.1
            on-link: true
  description: Mail Server LXD profile
  devices:
    eth0:
      ipv4.address: 192.168.7.201
      nictype: routed
      parent: eth0
      type: nic
cluster: null

Then I launch a container with:
lxc launch ubuntu:20.04 mail-server --profile default --profile mail-server

Now pinging anything on the internet from the guest doesn’t work.

root@mail-server:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
From 192.168.7.201 icmp_seq=1 Destination Host Unreachable

However it does work if I remove:

main.vm.provision "shell",
   run: "always",
  inline: "ip address add 192.168.7.201/24 dev eth1"

From the Vagrantfile. Any idea why is that BTW?

So here is some data about the final setup.

In the GUEST:

root@mail-server:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:db:f6:d2:02:7f brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.7.201/32 brd 255.255.255.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a8db:f6ff:fed2:27f/64 scope link 
       valid_lft forever preferred_lft forever

root@mail-server:~# ip r
default via 169.254.0.1 dev eth0 proto static onlink

In the HOST:

luken@test-luken-tech:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:be:4a:e8 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0
       valid_lft 84632sec preferred_lft 84632sec
    inet6 fe80::a00:27ff:febe:4ae8/64 scope link 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:79:ce:6c brd ff:ff:ff:ff:ff:ff
    inet 192.168.7.200/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet 192.168.7.201/24 scope global secondary eth1
       valid_lft forever preferred_lft forever
    inet 192.168.7.202/24 scope global secondary eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe79:ce6c/64 scope link 
       valid_lft forever preferred_lft forever
4: veth4d0dc658@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether fe:b7:0d:57:e7:a4 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 169.254.0.1/32 scope global veth4d0dc658
       valid_lft forever preferred_lft forever
    inet6 fe80::fcb7:dff:fe57:e7a4/64 scope link 
       valid_lft forever preferred_lft forever

luken@test-luken-tech:~$ ip r
default via 10.0.2.2 dev eth0 proto dhcp src 10.0.2.15 metric 100 
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 
10.0.2.2 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100 
192.168.7.0/24 dev eth1 proto kernel scope link src 192.168.7.200 
192.168.7.201 dev veth4d0dc658 scope link

My question is very simple, and I think answer for it would be extremely helpful for anyone starting his adventure with LXC containers and networking:

How to make the container accessible from my local computer under the IP 192.168.7.201 by using “routed” nictype? I assumed it will be pretty strightforward, but it doesn’t appear like that :confused: .

Ok, of course I figured it out after posting here, lol. I will post the answer for the future reference and for other people who may be stuck like me. So basically I had two things wrong.

  1. Containters IPs shouldn’t be added to the hosts interface. lxd will automagically set up correct routing, making containers IPs accessible in the network, assuming they belong to the same network.

  2. I had wrong value of the “parent:” setting in the lxd configuration above. “parent” should be an interface that connects host with your network. In my case it was “eth1”.

I hope it will help someone else :slight_smile: .

Glad you got it working. Yes you are correct the IPs must not be defined on the host, otherwise the host will ‘take’ the traffic that you want to go to the container.

Also see here for definitions for each config key https://linuxcontainers.org/lxd/docs/master/instances#nic-routed