From e39a5b2f8039d1cf2426bef5431b2fff43131bd1 Mon Sep 17 00:00:00 2001 From: Barnabas Busa Date: Tue, 15 Jul 2025 16:05:15 +0200 Subject: [PATCH 1/4] fix!: fine grained control over which service gets exposed using public publisher --- README.md | 35 +++++++-- src/cl/grandine/grandine_launcher.star | 2 +- src/cl/lighthouse/lighthouse_launcher.star | 2 +- src/cl/lodestar/lodestar_launcher.star | 2 +- src/cl/nimbus/nimbus_launcher.star | 2 +- src/cl/prysm/prysm_launcher.star | 2 +- src/cl/teku/teku_launcher.star | 2 +- src/el/besu/besu_launcher.star | 2 +- src/el/erigon/erigon_launcher.star | 2 +- src/el/ethereumjs/ethereumjs_launcher.star | 2 +- src/el/geth/geth_launcher.star | 2 +- src/el/nethermind/nethermind_launcher.star | 2 +- src/el/nimbus-eth1/nimbus_launcher.star | 2 +- src/el/reth/reth_launcher.star | 2 +- src/package_io/input_parser.star | 84 ++++++++++++++++------ 15 files changed, 106 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index ef2342314..4b036133e 100644 --- a/README.md +++ b/README.md @@ -1075,13 +1075,8 @@ ethereum_genesis_generator_params: # The image to use for ethereum genesis generator image: ethpandaops/ethereum-genesis-generator:4.1.16 -# Global parameter to set the exit ip address of services and public ports +# Per-service configuration to set the exit IP address and public ports port_publisher: - # if you have a service that you want to expose on a specific interface; set that IP here - # if you set it to auto it gets the public ip from ident.me and sets it - # Defaults to constants.PRIVATE_IP_ADDRESS_PLACEHOLDER - # The default value just means its the IP address of the container in which the service is running - nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Execution Layer public port exposed to your local machine # Disabled by default # Public port start defaults to 32000 @@ -1089,6 +1084,10 @@ port_publisher: el: enabled: false public_port_start: 32000 + # nat_exit_ip: IP address to expose for EL P2P networking + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Consensus Layer public port exposed to your local machine # Disabled by default # Public port start defaults to 33000 @@ -1096,6 +1095,10 @@ port_publisher: cl: enabled: false public_port_start: 33000 + # nat_exit_ip: IP address to expose for CL P2P networking + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Validator client public port exposed to your local machine # Disabled by default # Public port start defaults to 34000 @@ -1103,6 +1106,10 @@ port_publisher: vc: enabled: false public_port_start: 34000 + # nat_exit_ip: IP address to expose for VC networking + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # remote signer public port exposed to your local machine # Disabled by default # Public port start defaults to 35000 @@ -1110,6 +1117,10 @@ port_publisher: remote_signer: enabled: false public_port_start: 35000 + # nat_exit_ip: IP address to expose for remote signer networking + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Additional services public port exposed to your local machine # Disabled by default # Public port start defaults to 36000 @@ -1117,6 +1128,10 @@ port_publisher: additional_services: enabled: false public_port_start: 36000 + # nat_exit_ip: IP address to expose for additional services + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # MEV public port exposed to your local machine # Disabled by default @@ -1125,6 +1140,10 @@ port_publisher: mev: enabled: false public_port_start: 37000 + # nat_exit_ip: IP address to expose for MEV services + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Other public port exposed to your local machine (like ethereum metrics exporter, snooper) # Disabled by default @@ -1133,6 +1152,10 @@ port_publisher: other: enabled: false public_port_start: 38000 + # nat_exit_ip: IP address to expose for other services + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER ``` #### Example configurations diff --git a/src/cl/grandine/grandine_launcher.star b/src/cl/grandine/grandine_launcher.star index 98d111d40..21c639cad 100644 --- a/src/cl/grandine/grandine_launcher.star +++ b/src/cl/grandine/grandine_launcher.star @@ -237,7 +237,7 @@ def get_beacon_config( "--eth1-rpc-urls=" + EXECUTION_ENGINE_ENDPOINT, # ENR "--disable-enr-auto-update", - "--enr-address=" + port_publisher.nat_exit_ip, + "--enr-address=" + port_publisher.cl_nat_exit_ip, "--enr-udp-port={0}".format(discovery_port_udp), "--enr-tcp-port={0}".format(discovery_port_tcp), # QUIC diff --git a/src/cl/lighthouse/lighthouse_launcher.star b/src/cl/lighthouse/lighthouse_launcher.star index 4f6e13573..9547a1312 100644 --- a/src/cl/lighthouse/lighthouse_launcher.star +++ b/src/cl/lighthouse/lighthouse_launcher.star @@ -241,7 +241,7 @@ def get_beacon_config( "--suggested-fee-recipient=" + constants.VALIDATING_REWARDS_ACCOUNT, # ENR "--disable-enr-auto-update", - "--enr-address=" + port_publisher.nat_exit_ip, + "--enr-address=" + port_publisher.cl_nat_exit_ip, "--enr-tcp-port={0}".format(discovery_port_tcp), "--enr-udp-port={0}".format(discovery_port_udp), # QUIC diff --git a/src/cl/lodestar/lodestar_launcher.star b/src/cl/lodestar/lodestar_launcher.star index 12d35f9f0..20e95cfde 100644 --- a/src/cl/lodestar/lodestar_launcher.star +++ b/src/cl/lodestar/lodestar_launcher.star @@ -225,7 +225,7 @@ def get_beacon_config( "--nat=true", "--jwt-secret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, # ENR - "--enr.ip=" + port_publisher.nat_exit_ip, + "--enr.ip=" + port_publisher.cl_nat_exit_ip, "--enr.tcp={0}".format(discovery_port_tcp), "--enr.udp={0}".format(discovery_port_udp), # QUIC diff --git a/src/cl/nimbus/nimbus_launcher.star b/src/cl/nimbus/nimbus_launcher.star index e8a72c517..8981fdd98 100644 --- a/src/cl/nimbus/nimbus_launcher.star +++ b/src/cl/nimbus/nimbus_launcher.star @@ -242,7 +242,7 @@ def get_beacon_config( ), "--data-dir=" + BEACON_DATA_DIRPATH_ON_SERVICE_CONTAINER, "--web3-url=" + EXECUTION_ENGINE_ENDPOINT, - "--nat=extip:" + port_publisher.nat_exit_ip, + "--nat=extip:" + port_publisher.cl_nat_exit_ip, "--enr-auto-update=false", "--history={0}".format("archive" if constants.ARCHIVE_MODE else "prune"), "--rest", diff --git a/src/cl/prysm/prysm_launcher.star b/src/cl/prysm/prysm_launcher.star index 79d454928..62aa33be1 100644 --- a/src/cl/prysm/prysm_launcher.star +++ b/src/cl/prysm/prysm_launcher.star @@ -241,7 +241,7 @@ def get_beacon_config( "--http-host=0.0.0.0", "--http-cors-domain=*", "--http-port={0}".format(BEACON_HTTP_PORT_NUM), - "--p2p-host-ip=" + port_publisher.nat_exit_ip, + "--p2p-host-ip=" + port_publisher.cl_nat_exit_ip, "--p2p-tcp-port={0}".format(discovery_port_tcp), "--p2p-udp-port={0}".format(discovery_port_udp), "--p2p-quic-port={0}".format(discovery_port_quic), diff --git a/src/cl/teku/teku_launcher.star b/src/cl/teku/teku_launcher.star index 4d21a355c..e8ef19a41 100644 --- a/src/cl/teku/teku_launcher.star +++ b/src/cl/teku/teku_launcher.star @@ -223,7 +223,7 @@ def get_beacon_config( ), "--p2p-enabled=true", "--p2p-peer-lower-bound={0}".format(MIN_PEERS), - "--p2p-advertised-ip=" + port_publisher.nat_exit_ip, + "--p2p-advertised-ip=" + port_publisher.cl_nat_exit_ip, "--p2p-discovery-site-local-addresses-enabled=true", "--p2p-port={0}".format(discovery_port_tcp), "--rest-api-enabled=true", diff --git a/src/el/besu/besu_launcher.star b/src/el/besu/besu_launcher.star index d4fafd4f0..4d1d73f62 100644 --- a/src/el/besu/besu_launcher.star +++ b/src/el/besu/besu_launcher.star @@ -162,7 +162,7 @@ def get_config( "--rpc-ws-port={0}".format(WS_PORT_NUM), "--rpc-ws-api=ADMIN,CLIQUE,ETH,NET,DEBUG,TXPOOL,ENGINE,TRACE,WEB3", "--p2p-enabled=true", - "--p2p-host=" + port_publisher.nat_exit_ip, + "--p2p-host=" + port_publisher.el_nat_exit_ip, "--p2p-port={0}".format(discovery_port_tcp), "--engine-rpc-enabled=true", "--engine-jwt-secret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, diff --git a/src/el/erigon/erigon_launcher.star b/src/el/erigon/erigon_launcher.star index b31e31db2..269037f12 100644 --- a/src/el/erigon/erigon_launcher.star +++ b/src/el/erigon/erigon_launcher.star @@ -166,7 +166,7 @@ def get_config( "--http.vhosts=*", "--ws", "--allow-insecure-unlock", - "--nat=extip:" + port_publisher.nat_exit_ip, + "--nat=extip:" + port_publisher.el_nat_exit_ip, "--http", "--http.addr=0.0.0.0", "--http.corsdomain=*", diff --git a/src/el/ethereumjs/ethereumjs_launcher.star b/src/el/ethereumjs/ethereumjs_launcher.star index c87bbe397..2df87425c 100644 --- a/src/el/ethereumjs/ethereumjs_launcher.star +++ b/src/el/ethereumjs/ethereumjs_launcher.star @@ -174,7 +174,7 @@ def get_config( "--wsEnginePort={0}".format(WS_PORT_ENGINE_NUM), "--wsEngineAddr=0.0.0.0", "--jwt-secret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, - "--extIP={0}".format(port_publisher.nat_exit_ip), + "--extIP={0}".format(port_publisher.el_nat_exit_ip), "--sync=full", "--isSingleNode=true", "--logLevel={0}".format(log_level), diff --git a/src/el/geth/geth_launcher.star b/src/el/geth/geth_launcher.star index 350685f7e..00ae7ff4d 100644 --- a/src/el/geth/geth_launcher.star +++ b/src/el/geth/geth_launcher.star @@ -208,7 +208,7 @@ def get_config( "--ws.api=admin,engine,net,eth,web3,debug,txpool", "--ws.origins=*", "--allow-insecure-unlock", - "--nat=extip:" + port_publisher.nat_exit_ip, + "--nat=extip:" + port_publisher.el_nat_exit_ip, "--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM), "--authrpc.addr=0.0.0.0", "--authrpc.vhosts=*", diff --git a/src/el/nethermind/nethermind_launcher.star b/src/el/nethermind/nethermind_launcher.star index ab3eca470..b27625cf9 100644 --- a/src/el/nethermind/nethermind_launcher.star +++ b/src/el/nethermind/nethermind_launcher.star @@ -154,7 +154,7 @@ def get_config( "--JsonRpc.WebSocketsPort={0}".format(WS_PORT_NUM), "--JsonRpc.EngineHost=0.0.0.0", "--JsonRpc.EnginePort={0}".format(ENGINE_RPC_PORT_NUM), - "--Network.ExternalIp={0}".format(port_publisher.nat_exit_ip), + "--Network.ExternalIp={0}".format(port_publisher.el_nat_exit_ip), "--Network.DiscoveryPort={0}".format(discovery_port_tcp), "--Network.P2PPort={0}".format(discovery_port_tcp), "--JsonRpc.JwtSecretFile=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, diff --git a/src/el/nimbus-eth1/nimbus_launcher.star b/src/el/nimbus-eth1/nimbus_launcher.star index fe3e2aa71..8f72050dd 100644 --- a/src/el/nimbus-eth1/nimbus_launcher.star +++ b/src/el/nimbus-eth1/nimbus_launcher.star @@ -158,7 +158,7 @@ def get_config( "--metrics", "--metrics-address=0.0.0.0", "--metrics-port={0}".format(METRICS_PORT_NUM), - "--nat=extip:{0}".format(port_publisher.nat_exit_ip), + "--nat=extip:{0}".format(port_publisher.el_nat_exit_ip), "--tcp-port={0}".format(discovery_port_tcp), "--udp-port={0}".format(discovery_port_udp), ] diff --git a/src/el/reth/reth_launcher.star b/src/el/reth/reth_launcher.star index cbde55a19..62f129c34 100644 --- a/src/el/reth/reth_launcher.star +++ b/src/el/reth/reth_launcher.star @@ -202,7 +202,7 @@ def get_config( "--ws.port={0}".format(WS_PORT_NUM), "--ws.api=net,eth", "--ws.origins=*", - "--nat=extip:" + port_publisher.nat_exit_ip, + "--nat=extip:" + port_publisher.el_nat_exit_ip, "--authrpc.port={0}".format(ENGINE_RPC_PORT_NUM), "--authrpc.jwtsecret=" + constants.JWT_MOUNT_PATH_ON_CONTAINER, "--authrpc.addr=0.0.0.0", diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index eae038723..efb056e07 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -229,8 +229,21 @@ def input_parser(plan, input_args): else: plan.print("Docker cache is disabled") - if result["port_publisher"]["nat_exit_ip"] == "auto": - result["port_publisher"]["nat_exit_ip"] = get_public_ip(plan) + # Auto-detect public IP for each service group that has nat_exit_ip set to "auto" + public_ip = None + for service_group in [ + "el", + "cl", + "vc", + "remote_signer", + "additional_services", + "mev", + "other", + ]: + if result["port_publisher"][service_group]["nat_exit_ip"] == "auto": + if public_ip == None: + public_ip = get_public_ip(plan) + result["port_publisher"][service_group]["nat_exit_ip"] = public_ip if "prometheus_grafana" in result["additional_services"]: plan.print( @@ -572,29 +585,39 @@ def input_parser(plan, input_args): image=result["ethereum_genesis_generator_params"]["image"], ), port_publisher=struct( - nat_exit_ip=result["port_publisher"]["nat_exit_ip"], cl_enabled=result["port_publisher"]["cl"]["enabled"], cl_public_port_start=result["port_publisher"]["cl"]["public_port_start"], + cl_nat_exit_ip=result["port_publisher"]["cl"]["nat_exit_ip"], el_enabled=result["port_publisher"]["el"]["enabled"], el_public_port_start=result["port_publisher"]["el"]["public_port_start"], + el_nat_exit_ip=result["port_publisher"]["el"]["nat_exit_ip"], vc_enabled=result["port_publisher"]["vc"]["enabled"], vc_public_port_start=result["port_publisher"]["vc"]["public_port_start"], + vc_nat_exit_ip=result["port_publisher"]["vc"]["nat_exit_ip"], remote_signer_enabled=result["port_publisher"]["remote_signer"]["enabled"], remote_signer_public_port_start=result["port_publisher"]["remote_signer"][ "public_port_start" ], + remote_signer_nat_exit_ip=result["port_publisher"]["remote_signer"][ + "nat_exit_ip" + ], additional_services_enabled=result["port_publisher"]["additional_services"][ "enabled" ], additional_services_public_port_start=result["port_publisher"][ "additional_services" ]["public_port_start"], + additional_services_nat_exit_ip=result["port_publisher"][ + "additional_services" + ]["nat_exit_ip"], mev_enabled=result["port_publisher"]["mev"]["enabled"], mev_public_port_start=result["port_publisher"]["mev"]["public_port_start"], + mev_nat_exit_ip=result["port_publisher"]["mev"]["nat_exit_ip"], other_enabled=result["port_publisher"]["other"]["enabled"], other_public_port_start=result["port_publisher"]["other"][ "public_port_start" ], + other_nat_exit_ip=result["port_publisher"]["other"]["nat_exit_ip"], ), ) @@ -1445,28 +1468,49 @@ def get_default_custom_flood_params(): def get_port_publisher_params(parameter_type, input_args=None): port_publisher_parameters = { - "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", - "el": {"enabled": False, "public_port_start": 32000}, - "cl": {"enabled": False, "public_port_start": 33000}, - "vc": {"enabled": False, "public_port_start": 34000}, - "remote_signer": {"enabled": False, "public_port_start": 35000}, - "additional_services": {"enabled": False, "public_port_start": 36000}, - "mev": {"enabled": False, "public_port_start": 37000}, - "other": {"enabled": False, "public_port_start": 38000}, + "el": { + "enabled": False, + "public_port_start": 32000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, + "cl": { + "enabled": False, + "public_port_start": 33000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, + "vc": { + "enabled": False, + "public_port_start": 34000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, + "remote_signer": { + "enabled": False, + "public_port_start": 35000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, + "additional_services": { + "enabled": False, + "public_port_start": 36000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, + "mev": { + "enabled": False, + "public_port_start": 37000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, + "other": { + "enabled": False, + "public_port_start": 38000, + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", + }, } if parameter_type == "default": return port_publisher_parameters else: for setting in input_args["port_publisher"]: - if setting == "nat_exit_ip": - nat_exit_ip_value = input_args["port_publisher"][setting] - port_publisher_parameters[setting] = nat_exit_ip_value - else: - for sub_setting in input_args["port_publisher"][setting]: - sub_setting_value = input_args["port_publisher"][setting][ - sub_setting - ] - port_publisher_parameters[setting][sub_setting] = sub_setting_value + for sub_setting in input_args["port_publisher"][setting]: + sub_setting_value = input_args["port_publisher"][setting][sub_setting] + port_publisher_parameters[setting][sub_setting] = sub_setting_value return port_publisher_parameters From e3e83573d051716d42293deacd2d75c8d5799712 Mon Sep 17 00:00:00 2001 From: Barnabas Busa Date: Tue, 15 Jul 2025 16:28:49 +0200 Subject: [PATCH 2/4] fix, make it backwards compatible --- .github/tests/mix-public.yaml | 1 + README.md | 88 +++++++++++++++++++++++++++++--- network_params.yaml | 3 ++ src/package_io/input_parser.star | 65 ++++++++++++++++------- 4 files changed, 131 insertions(+), 26 deletions(-) diff --git a/.github/tests/mix-public.yaml b/.github/tests/mix-public.yaml index 5a97ad357..0a00ddd52 100644 --- a/.github/tests/mix-public.yaml +++ b/.github/tests/mix-public.yaml @@ -15,6 +15,7 @@ participants: - el_type: ethereumjs cl_type: grandine port_publisher: + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER el: enabled: true public_port_start: 40000 diff --git a/README.md b/README.md index 4b036133e..ac5e5ac0c 100644 --- a/README.md +++ b/README.md @@ -1075,8 +1075,14 @@ ethereum_genesis_generator_params: # The image to use for ethereum genesis generator image: ethpandaops/ethereum-genesis-generator:4.1.16 -# Per-service configuration to set the exit IP address and public ports +# Configuration for public ports and NAT exit IP addresses port_publisher: + # Global NAT exit IP address for all services (optional) + # If set, this will be used for all service groups (overrides individual nat_exit_ip settings) + # Set to "auto" to automatically detect public IP from ident.me + # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (uses per-service settings) + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER + # Execution Layer public port exposed to your local machine # Disabled by default # Public port start defaults to 32000 @@ -1084,10 +1090,12 @@ port_publisher: el: enabled: false public_port_start: 32000 - # nat_exit_ip: IP address to expose for EL P2P networking + # nat_exit_ip: IP address to expose for EL P2P networking (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER + # Consensus Layer public port exposed to your local machine # Disabled by default # Public port start defaults to 33000 @@ -1095,10 +1103,12 @@ port_publisher: cl: enabled: false public_port_start: 33000 - # nat_exit_ip: IP address to expose for CL P2P networking + # nat_exit_ip: IP address to expose for CL P2P networking (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER + # Validator client public port exposed to your local machine # Disabled by default # Public port start defaults to 34000 @@ -1106,10 +1116,12 @@ port_publisher: vc: enabled: false public_port_start: 34000 - # nat_exit_ip: IP address to expose for VC networking + # nat_exit_ip: IP address to expose for VC networking (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER + # remote signer public port exposed to your local machine # Disabled by default # Public port start defaults to 35000 @@ -1117,10 +1129,12 @@ port_publisher: remote_signer: enabled: false public_port_start: 35000 - # nat_exit_ip: IP address to expose for remote signer networking + # nat_exit_ip: IP address to expose for remote signer networking (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER + # Additional services public port exposed to your local machine # Disabled by default # Public port start defaults to 36000 @@ -1128,7 +1142,8 @@ port_publisher: additional_services: enabled: false public_port_start: 36000 - # nat_exit_ip: IP address to expose for additional services + # nat_exit_ip: IP address to expose for additional services (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER @@ -1140,7 +1155,8 @@ port_publisher: mev: enabled: false public_port_start: 37000 - # nat_exit_ip: IP address to expose for MEV services + # nat_exit_ip: IP address to expose for MEV services (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER @@ -1152,7 +1168,8 @@ port_publisher: other: enabled: false public_port_start: 38000 - # nat_exit_ip: IP address to expose for other services + # nat_exit_ip: IP address to expose for other services (optional) + # Only used if global nat_exit_ip is not set # Set to "auto" to automatically detect public IP from ident.me # Defaults to KURTOSIS_IP_ADDR_PLACEHOLDER (container IP) nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER @@ -1160,6 +1177,61 @@ port_publisher: #### Example configurations +
+ Port Publisher Configuration Examples + +**Global NAT Exit IP (Backward Compatible)** +```yaml +port_publisher: + nat_exit_ip: "auto" # All services use auto-detected public IP + el: + enabled: true + public_port_start: 32000 + cl: + enabled: true + public_port_start: 33000 + additional_services: + enabled: true + public_port_start: 36000 +``` + +**Per-Service NAT Exit IP (Granular Control)** +```yaml +port_publisher: + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Not set globally + el: + enabled: true + public_port_start: 32000 + nat_exit_ip: "auto" # Only EL uses public IP + cl: + enabled: true + public_port_start: 33000 + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # CL uses container IP + additional_services: + enabled: true + public_port_start: 36000 + nat_exit_ip: "192.168.1.100" # Custom IP for additional services +``` + +**Mixed Configuration** +```yaml +port_publisher: + nat_exit_ip: KURTOSIS_IP_ADDR_PLACEHOLDER # Not set globally + el: + enabled: true + public_port_start: 32000 + nat_exit_ip: "auto" # Auto-detect for EL + cl: + enabled: true + public_port_start: 33000 + nat_exit_ip: "auto" # Auto-detect for CL + additional_services: + enabled: true + public_port_start: 36000 + # Uses default KURTOSIS_IP_ADDR_PLACEHOLDER for additional services +``` +
+
Verkle configuration example diff --git a/network_params.yaml b/network_params.yaml index 5a62a9514..b95cf7cf9 100644 --- a/network_params.yaml +++ b/network_params.yaml @@ -227,3 +227,6 @@ port_publisher: mev: enabled: false public_port_start: 37000 + other: + enabled: false + public_port_start: 38000 diff --git a/src/package_io/input_parser.star b/src/package_io/input_parser.star index efb056e07..5d09bc31e 100644 --- a/src/package_io/input_parser.star +++ b/src/package_io/input_parser.star @@ -229,21 +229,40 @@ def input_parser(plan, input_args): else: plan.print("Docker cache is disabled") - # Auto-detect public IP for each service group that has nat_exit_ip set to "auto" - public_ip = None - for service_group in [ - "el", - "cl", - "vc", - "remote_signer", - "additional_services", - "mev", - "other", - ]: - if result["port_publisher"][service_group]["nat_exit_ip"] == "auto": - if public_ip == None: - public_ip = get_public_ip(plan) - result["port_publisher"][service_group]["nat_exit_ip"] = public_ip + # Handle global nat_exit_ip setting - if set, apply to all service groups + if result["port_publisher"]["nat_exit_ip"] != "KURTOSIS_IP_ADDR_PLACEHOLDER": + global_nat_exit_ip = result["port_publisher"]["nat_exit_ip"] + if global_nat_exit_ip == "auto": + global_nat_exit_ip = get_public_ip(plan) + result["port_publisher"]["nat_exit_ip"] = global_nat_exit_ip + + # Set all service groups to use the global value + for service_group in [ + "el", + "cl", + "vc", + "remote_signer", + "additional_services", + "mev", + "other", + ]: + result["port_publisher"][service_group]["nat_exit_ip"] = global_nat_exit_ip + else: + # Auto-detect public IP for each service group that has nat_exit_ip set to "auto" + public_ip = None + for service_group in [ + "el", + "cl", + "vc", + "remote_signer", + "additional_services", + "mev", + "other", + ]: + if result["port_publisher"][service_group]["nat_exit_ip"] == "auto": + if public_ip == None: + public_ip = get_public_ip(plan) + result["port_publisher"][service_group]["nat_exit_ip"] = public_ip if "prometheus_grafana" in result["additional_services"]: plan.print( @@ -585,6 +604,7 @@ def input_parser(plan, input_args): image=result["ethereum_genesis_generator_params"]["image"], ), port_publisher=struct( + nat_exit_ip=result["port_publisher"]["nat_exit_ip"], cl_enabled=result["port_publisher"]["cl"]["enabled"], cl_public_port_start=result["port_publisher"]["cl"]["public_port_start"], cl_nat_exit_ip=result["port_publisher"]["cl"]["nat_exit_ip"], @@ -1468,6 +1488,7 @@ def get_default_custom_flood_params(): def get_port_publisher_params(parameter_type, input_args=None): port_publisher_parameters = { + "nat_exit_ip": "KURTOSIS_IP_ADDR_PLACEHOLDER", "el": { "enabled": False, "public_port_start": 32000, @@ -1508,9 +1529,17 @@ def get_port_publisher_params(parameter_type, input_args=None): return port_publisher_parameters else: for setting in input_args["port_publisher"]: - for sub_setting in input_args["port_publisher"][setting]: - sub_setting_value = input_args["port_publisher"][setting][sub_setting] - port_publisher_parameters[setting][sub_setting] = sub_setting_value + if setting == "nat_exit_ip": + # Handle global nat_exit_ip setting + nat_exit_ip_value = input_args["port_publisher"][setting] + port_publisher_parameters[setting] = nat_exit_ip_value + else: + # Handle service group settings + for sub_setting in input_args["port_publisher"][setting]: + sub_setting_value = input_args["port_publisher"][setting][ + sub_setting + ] + port_publisher_parameters[setting][sub_setting] = sub_setting_value return port_publisher_parameters From 131057738761c530dcb9e275632466e79ee36ca4 Mon Sep 17 00:00:00 2001 From: Barnabas Busa Date: Wed, 16 Jul 2025 12:41:16 +0200 Subject: [PATCH 3/4] fix additional services --- src/blobscan/blobscan_launcher.star | 19 ++++++++++++++++- src/blockscout/blockscout_launcher.star | 21 +++++++++++++++++-- .../full_beaconchain_launcher.star | 20 ++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/blobscan/blobscan_launcher.star b/src/blobscan/blobscan_launcher.star index a325adf5d..076116e6f 100644 --- a/src/blobscan/blobscan_launcher.star +++ b/src/blobscan/blobscan_launcher.star @@ -10,6 +10,22 @@ SECRET_KEY = "supersecure" WEB_HTTP_PORT_NUMBER = 3000 API_HTTP_PORT_NUMBER = 3001 + +def get_blobscan_api_host(blobscan_config, port_publisher): + if port_publisher.additional_services_enabled: + return port_publisher.additional_services_nat_exit_ip + return blobscan_config.ip_address + + +def get_blobscan_api_port(blobscan_config, port_publisher): + if port_publisher.additional_services_enabled: + public_ports = shared_utils.get_public_ports_for_component( + "additional_services", port_publisher, 0 + ) + return public_ports[1] # Second port for the API (first is web) + return blobscan_config.ports[constants.HTTP_PORT_ID].number + + WEB_PORTS = { constants.HTTP_PORT_ID: shared_utils.new_port_spec( WEB_HTTP_PORT_NUMBER, @@ -116,7 +132,8 @@ def launch_blobscan( blobscan_config = plan.add_service(API_SERVICE_NAME, api_config) blobscan_api_url = "http://{0}:{1}".format( - blobscan_config.ip_address, blobscan_config.ports[constants.HTTP_PORT_ID].number + get_blobscan_api_host(blobscan_config, port_publisher), + get_blobscan_api_port(blobscan_config, port_publisher), ) web_config = get_web_config( diff --git a/src/blockscout/blockscout_launcher.star b/src/blockscout/blockscout_launcher.star index f54fd9910..a59b50ed1 100644 --- a/src/blockscout/blockscout_launcher.star +++ b/src/blockscout/blockscout_launcher.star @@ -9,6 +9,23 @@ SERVICE_NAME_FRONTEND = "blockscout-frontend" HTTP_PORT_NUMBER = 4000 HTTP_PORT_NUMBER_VERIF = 8050 HTTP_PORT_NUMBER_FRONTEND = 3000 + + +def get_api_host(blockscout_service, port_publisher): + if port_publisher.additional_services_enabled: + return port_publisher.additional_services_nat_exit_ip + return blockscout_service.ip_address + + +def get_api_port(blockscout_service, port_publisher): + if port_publisher.additional_services_enabled: + public_ports = shared_utils.get_public_ports_for_component( + "additional_services", port_publisher, 0 + ) + return public_ports[0] # First port for the API + return blockscout_service.ports["http"].number + + BLOCKSCOUT_MIN_CPU = 100 BLOCKSCOUT_MAX_CPU = 1000 BLOCKSCOUT_MIN_MEMORY = 1024 @@ -238,9 +255,9 @@ def get_config_frontend( "NEXT_PUBLIC_NETWORK_NAME": "Kurtosis", "NEXT_PUBLIC_NETWORK_ID": network_params.network_id, "NEXT_PUBLIC_NETWORK_RPC_URL": el_client_rpc_url, - "NEXT_PUBLIC_API_HOST": blockscout_service.ip_address + "NEXT_PUBLIC_API_HOST": get_api_host(blockscout_service, port_publisher) + ":" - + str(blockscout_service.ports["http"].number), + + str(get_api_port(blockscout_service, port_publisher)), "NEXT_PUBLIC_AD_BANNER_PROVIDER": "none", "NEXT_PUBLIC_AD_TEXT_PROVIDER": "none", "NEXT_PUBLIC_IS_TESTNET": "true", diff --git a/src/full_beaconchain/full_beaconchain_launcher.star b/src/full_beaconchain/full_beaconchain_launcher.star index 92d90ebba..1fb77d890 100644 --- a/src/full_beaconchain/full_beaconchain_launcher.star +++ b/src/full_beaconchain/full_beaconchain_launcher.star @@ -18,6 +18,22 @@ LITTLE_BIGTABLE_PORT_NUMBER = 9000 FULL_BEACONCHAIN_CONFIG_FILENAME = "beaconchain-config.yml" + +def get_little_bigtable_host(little_bigtable, port_publisher): + if port_publisher.additional_services_enabled: + return port_publisher.additional_services_nat_exit_ip + return little_bigtable.ip_address + + +def get_little_bigtable_port(little_bigtable, port_publisher): + if port_publisher.additional_services_enabled: + public_ports = shared_utils.get_public_ports_for_component( + "additional_services", port_publisher, 0 + ) + return public_ports[0] # Use first port for little bigtable + return LITTLE_BIGTABLE_PORT_NUMBER + + # The min/max CPU/memory that postgres can use POSTGRES_MIN_CPU = 10 POSTGRES_MAX_CPU = 1000 @@ -133,8 +149,8 @@ def launch_full_beacon( cl_contexts[0].http_port, cl_contexts[0].client_name, el_uri, - little_bigtable.ip_address, - LITTLE_BIGTABLE_PORT_NUMBER, + get_little_bigtable_host(little_bigtable, port_publisher), + get_little_bigtable_port(little_bigtable, port_publisher), postgres_output.service.name, POSTGRES_PORT_NUMBER, redis_url, From 4dbb83041d5d52771417553bdb8e0728f7c0bda4 Mon Sep 17 00:00:00 2001 From: Barnabas Busa Date: Wed, 16 Jul 2025 14:51:14 +0200 Subject: [PATCH 4/4] fix --- src/blockscout/blockscout_launcher.star | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/blockscout/blockscout_launcher.star b/src/blockscout/blockscout_launcher.star index a59b50ed1..1aa3eb64d 100644 --- a/src/blockscout/blockscout_launcher.star +++ b/src/blockscout/blockscout_launcher.star @@ -127,6 +127,7 @@ def launch_blockscout( network_params, global_node_selectors, blockscout_service, + port_publisher, ) plan.add_service(SERVICE_NAME_FRONTEND, config_frontend) return blockscout_url @@ -240,6 +241,7 @@ def get_config_frontend( network_params, node_selectors, blockscout_service, + port_publisher, ): return ServiceConfig( image=shared_utils.docker_cache_image_calc(