diff --git a/app/api/network.py b/app/api/network.py
index ee16cd0c9fa620efc1525c5c8d5955cd10dce16b..a2932543a11f3f239c9bb84ab17e92c8b4e5b03e 100644
--- a/app/api/network.py
+++ b/app/api/network.py
@@ -163,7 +163,7 @@ def create_interface():
     .. :quickref: Network; Create new interface
 
     :jsonparam network: network name
-    :jsonparam ip: interface IP
+    :jsonparam ip: (optional) interface IP - IP will be assigned automatically if not given
     :jsonparam name: interface name
     :jsonparam host: host name
     :jsonparam mac: (optional) MAC address
@@ -185,7 +185,7 @@ def create_interface():
         if not current_user.has_access_to_network(network):
             raise CSEntryError("User doesn't have the required group", status_code=403)
     return utils.create_generic_model(
-        models.Interface, mandatory_fields=("network", "ip", "name", "host")
+        models.Interface, mandatory_fields=("network", "name", "host")
     )
 
 
diff --git a/app/models.py b/app/models.py
index a71ee67c381a1dbc2e6ec34fa23d0c4aae4179a6..5c6d5c33aebf6bbf555d33fd74203da38ed300ef 100644
--- a/app/models.py
+++ b/app/models.py
@@ -1457,9 +1457,9 @@ class Interface(CreatedMixin, db.Model):
         try:
             ip = kwargs.pop("ip")
         except KeyError:
-            super().__init__(host=host, **kwargs)
-        else:
-            super().__init__(host=host, ip=ip, **kwargs)
+            # Assign first available IP
+            ip = str(kwargs["network"].available_ips()[0])
+        super().__init__(host=host, ip=ip, **kwargs)
 
     @validates("name")
     def validate_name(self, key, string):
diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py
index 324645edaf229b86249fd62496b04011df6a41ac..57b6d07d98f69f8b30322b75b06ea5feb300509b 100644
--- a/tests/functional/test_api.py
+++ b/tests/functional/test_api.py
@@ -181,6 +181,17 @@ def no_login_check_token(request, app):
     app.config["LOGIN_DISABLED"] = False
 
 
+@pytest.fixture
+def network_192_168_1(network_scope_factory, network_factory):
+    scope = network_scope_factory(supernet="192.168.0.0/16")
+    return network_factory(
+        address="192.168.1.0/24",
+        first_ip="192.168.1.10",
+        last_ip="192.168.1.250",
+        scope=scope,
+    )
+
+
 def check_response_message(response, msg, status_code=400):
     assert response.status_code == status_code
     try:
@@ -1124,16 +1135,7 @@ def test_get_interfaces_with_sensitive_network(
     assert len(response.get_json()) == 1
 
 
-def test_create_interface_fails(
-    client, host, network_scope_factory, network_factory, no_login_check_token
-):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
+def test_create_interface_fails(client, host, network_192_168_1, no_login_check_token):
     # check that network_id and ip are mandatory
     response = post(
         client, f"{API_URL}/network/interfaces", data={}, token=no_login_check_token
@@ -1146,15 +1148,12 @@ def test_create_interface_fails(
         token=no_login_check_token,
     )
     check_response_message(response, "Missing mandatory field 'network'", 422)
-    response = post(
-        client,
-        f"{API_URL}/network/interfaces",
-        data={"network": network.address},
-        token=no_login_check_token,
-    )
-    check_response_message(response, "Missing mandatory field 'ip'", 422)
 
-    data = {"network": network.vlan_name, "ip": "192.168.1.20", "name": "interface1"}
+    data = {
+        "network": network_192_168_1.vlan_name,
+        "ip": "192.168.1.20",
+        "name": "interface1",
+    }
     response = post(
         client, f"{API_URL}/network/interfaces", data=data, token=no_login_check_token
     )
@@ -1169,18 +1168,9 @@ def test_create_interface_fails(
     )
 
 
-def test_create_interface(
-    client, host, network_scope_factory, network_factory, no_login_check_token
-):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
+def test_create_interface(client, host, network_192_168_1, no_login_check_token):
     data = {
-        "network": network.vlan_name,
+        "network": network_192_168_1.vlan_name,
         "ip": "192.168.1.20",
         "name": host.name,
         "host": host.name,
@@ -1190,7 +1180,7 @@ def test_create_interface(
     )
     assert response.status_code == 201
     assert INTERFACE_KEYS == set(response.get_json().keys())
-    assert response.get_json()["network"] == network.vlan_name
+    assert response.get_json()["network"] == network_192_168_1.vlan_name
     assert response.get_json()["ip"] == "192.168.1.20"
     assert response.get_json()["name"] == host.name
     # This is the main interface
@@ -1198,7 +1188,7 @@ def test_create_interface(
 
     # Check that all parameters can be passed
     data2 = {
-        "network": network.vlan_name,
+        "network": network_192_168_1.vlan_name,
         "ip": "192.168.1.21",
         "name": host.name + "-2",
         "host": host.name,
@@ -1227,18 +1217,11 @@ def test_create_interface(
 
 @pytest.mark.parametrize("ip", ("", "foo", "192.168"))
 def test_create_interface_invalid_ip(
-    ip, client, host, network_scope_factory, network_factory, no_login_check_token
+    ip, client, host, network_192_168_1, no_login_check_token
 ):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
     # invalid IP address
     data = {
-        "network": network.vlan_name,
+        "network": network_192_168_1.vlan_name,
         "ip": ip,
         "name": host.name,
         "host": host.name,
@@ -1252,18 +1235,11 @@ def test_create_interface_invalid_ip(
 
 
 def test_create_interface_ip_not_in_network(
-    client, host, network_scope_factory, network_factory, no_login_check_token
+    client, host, network_192_168_1, no_login_check_token
 ):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
     # IP address not in range
     data = {
-        "network": network.vlan_name,
+        "network": network_192_168_1.vlan_name,
         "ip": "192.168.2.4",
         "name": host.name,
         "host": host.name,
@@ -1277,18 +1253,11 @@ def test_create_interface_ip_not_in_network(
 
 
 def test_create_interface_ip_not_in_range(
-    client, host, network_scope_factory, network_factory, no_login_check_token
+    client, host, network_192_168_1, no_login_check_token
 ):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
     # IP address not in range
     data = {
-        "network": network.vlan_name,
+        "network": network_192_168_1.vlan_name,
         "ip": "192.168.1.4",
         "name": host.name,
         "host": host.name,
@@ -1304,18 +1273,11 @@ def test_create_interface_ip_not_in_range(
 
 
 def test_create_interface_ip_not_in_range_as_admin(
-    client, host, network_scope_factory, network_factory, admin_token
+    client, host, network_192_168_1, admin_token
 ):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
     # IP address not in range
     data = {
-        "network": network.vlan_name,
+        "network": network_192_168_1.vlan_name,
         "ip": "192.168.1.4",
         "name": host.name,
         "host": host.name,
@@ -1353,6 +1315,37 @@ def test_normal_user_can_create_interface_on_empty_host(
     assert response.get_json()["is_main"]
 
 
+def test_create_interface_with_ip(
+    client, host, network_192_168_1, no_login_check_token
+):
+    data = {
+        "network": network_192_168_1.vlan_name,
+        "name": host.name,
+        "host": host.name,
+        "ip": "192.168.1.12",
+    }
+    response = post(
+        client, f"{API_URL}/network/interfaces", data=data, token=no_login_check_token
+    )
+    assert response.status_code == 201
+    assert response.get_json()["ip"] == "192.168.1.12"
+
+
+def test_create_interface_without_ip(
+    client, host, network_192_168_1, no_login_check_token
+):
+    data = {
+        "network": network_192_168_1.vlan_name,
+        "name": host.name,
+        "host": host.name,
+    }
+    response = post(
+        client, f"{API_URL}/network/interfaces", data=data, token=no_login_check_token
+    )
+    assert response.status_code == 201
+    assert response.get_json()["ip"] == "192.168.1.10"
+
+
 def test_delete_interface_invalid_credentials(client, interface_factory, user_token):
     interface1 = interface_factory()
     response = delete(
@@ -2291,17 +2284,8 @@ def test_patch_interface_mac(client, interface_factory, admin_token):
     assert updated_interface.mac == data["mac"]
 
 
-def test_patch_interface_ip(
-    client, interface_factory, network_scope_factory, network_factory, admin_token
-):
-    scope = network_scope_factory(supernet="192.168.0.0/16")
-    network = network_factory(
-        address="192.168.1.0/24",
-        first_ip="192.168.1.10",
-        last_ip="192.168.1.250",
-        scope=scope,
-    )
-    interface = interface_factory(network=network, ip="192.168.1.11")
+def test_patch_interface_ip(client, interface_factory, network_192_168_1, admin_token):
+    interface = interface_factory(network=network_192_168_1, ip="192.168.1.11")
     data = {"ip": "192.168.2.12"}
     response = patch(
         client,
@@ -2310,7 +2294,9 @@ def test_patch_interface_ip(
         token=admin_token,
     )
     check_response_message(
-        response, f"IP address {data['ip']} is not in network {network.address}", 422
+        response,
+        f"IP address {data['ip']} is not in network {network_192_168_1.address}",
+        422,
     )
     data = {"ip": "192.168.1.12"}
     response = patch(