Service
The service resource provides HTTP/HTTPS proxy access to web applications running in sandbox resources such as containers and VMs. It creates browser-accessible tabs that route traffic to services within the lab environment, enabling users to interact with web applications, APIs, and dashboards.
Use Cases
Section titled “Use Cases”As a lab author, you can use service resources to provide web access:
- Web Application Access: Expose web applications, dashboards, and user interfaces for hands-on interaction
- Development Tools: Access code editors, database admin tools (e.g. pgAdmin), monitoring dashboards (e.g. Grafana)
- Multi-Port Services: Expose different services from the same container or VM on different ports (e.g. frontend and API)
Service resources bridge the gap between isolated lab environments and user browser access, enabling realistic web application scenarios.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”resource "service" "name" { target = resource.container.webapp port = 8080}Full Syntax
Section titled “Full Syntax”resource "service" "name" { target = resource.container.webapp scheme = "http" port = 8080 path = "/app" open_in_new_window = true
custom_request_headers = { "X-Api-Key" = "secret" }
custom_response_headers = { "Cache-Control" = "no-store" }}Fields
| Field | Type | Required | Description |
|---|---|---|---|
target | referencecontainer, vm, k8s_cluster, kubernetes_cluster, nomad_cluster, ingress | ✓ | Select the container where your web application or API is running. The service tab will proxy HTTP/HTTPS requests to this container. |
port | number | ✓ | Specify the port where your application listens for connections inside the container ConstraintsMinimum 1; Maximum 65535 |
scheme | string | — | Choose whether to connect using HTTP or HTTPS. Use HTTPS if your application has TLS/SSL enabled. Allowed http httpsDefault http |
path | string | — | Optional. Set a default path if your application serves content from a subdirectory (e.g., /api or /dashboard). ConstraintsPath must begin with / |
open_ | bool | — | Enable this if the application can't be embedded in an iframe, or learners should use it outside the lab UI. When true, the tab opens the service in a new window with full browser functionality. Default false |
custom_ | map(string) | — | Headers the proxy adds to each request before it reaches your application, e.g. an API key. A Host header also replaces the host the request is sent with. |
custom_ | map(string) | — | Headers the proxy adds to each response before it reaches the learner's browser, e.g. Cache-Control. |
Examples
Section titled “Examples”Basic HTTP Service
Section titled “Basic HTTP Service”resource "service" "webapp" { target = resource.container.app port = 3000}HTTPS Service with Path
Section titled “HTTPS Service with Path”resource "service" "dashboard" { target = resource.container.monitoring scheme = "https" port = 3000 path = "/dashboard"}VM Service
Section titled “VM Service”resource "service" "vm_dashboard" { target = resource.vm.devbox port = 8080 path = "/dashboard"}Custom HTTP Headers
Section titled “Custom HTTP Headers”resource "service" "api" { target = resource.container.app port = 8080
custom_request_headers = { "Authorization" = "Bearer ${variable.api_token}" }
custom_response_headers = { "Cache-Control" = "no-store" }}custom_request_headersare added to every request the proxy sends to the service. AHostheader also replaces the host the request is sent with.custom_response_headersare added to every response before it reaches the learner’s browser. AContent-Security-Policyset here replaces the default one.- A header with the same name as an existing one replaces it.
Multiple Services from One Container
Section titled “Multiple Services from One Container”resource "container" "multiservice" { image { name = "myapp:latest" }
port { local = 8080 }
port { local = 8081 }}
resource "service" "app_ui" { target = resource.container.multiservice port = 8080}
resource "service" "app_api" { target = resource.container.multiservice port = 8081 path = "/api/v1"}Service in Layout
Section titled “Service in Layout”resource "layout" "default" { column { width = "50" instructions {} }
column { width = "50"
tab "webapp" { target = resource.service.webapp title = "Web Application" } }}Display Behavior
Section titled “Display Behavior”Embedded (Default)
Section titled “Embedded (Default)”When open_in_new_window = false:
- Service loads in an iframe within the lab tab
- Users stay within the lab environment
New Window
Section titled “New Window”When open_in_new_window = true:
- Service opens in a new browser window/tab
- Full browser functionality available
- Users can switch between lab and service
Kubernetes Access Pattern
Section titled “Kubernetes Access Pattern”When you want a controlled browser entry point for Kubernetes API access, use a proxy container:
# Proxy container for Kubernetes dashboardresource "container" "k8s_proxy" { image { name = "bitnami/kubectl:latest" }
command = ["kubectl", "proxy", "--address=0.0.0.0", "--port=8001", "--accept-hosts=.*"]
network { id = resource.network.main.meta.id }
volume { source = resource.k8s_cluster.k8s.kube_config.path destination = "/root/.kube/config" type = "bind" }
port { local = 8001 }}
# Service pointing to the proxy containerresource "service" "k8s_dashboard" { target = resource.container.k8s_proxy port = 8001 path = "/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/"}Best Practices
Section titled “Best Practices”- Use Meaningful Names: Name your service resources based on their function (e.g.,
webapp,api,dashboard) - Consistent Schemes: Use HTTPS for services when certificates are properly configured
- Path Configuration: Use the
pathfield to route to specific application paths - Port Documentation: Document which ports your services use in comments
- Health Checks: Ensure the target resource has health checks configured for service availability
Common Issues
Section titled “Common Issues”-
Target Type Error: “target can only be of the following types: container, vm, k8s_cluster, kubernetes_cluster, nomad_cluster, ingress”
- Solution: Ensure you’re referencing a supported sandbox resource
-
Service Not Accessible: Service loads but shows connection errors
- Check that the target resource is running and healthy
- Verify the port number matches the service’s actual listening port
- Ensure the target exposes the port in its configuration
-
HTTPS Certificate Issues: When using scheme “https”
- The service must have valid SSL certificates configured
- Consider using “http” for development/testing scenarios
