Linux Headless Mode
Linux Headless Mode
The Twingate Client for Linux may be run in headless mode, allowing it to be used in environments where a graphical user interface is not available. This is particularly useful in server environments where the Client is required to run as a background service.
Twingate’s Linux Client may be used in either interactive mode or headless mode.
- Interactive mode is the default mode and is documented in our Linux Client documentation. The same platform support and installation instructions apply.
- Headless mode is accessed by passing a
--headless
parameter to thetwingate setup
command with the path to a valid Service Key specified. The Service Key is obtained from the Service configuration in the Twingate Admin console.
Supported distributions
The Twingate Linux Client currently supports the following Linux distributions for x86/AMD64 and ARM64-based devices:
- Ubuntu (20.04 LTS and 22.04, limited support for 24.04)
- Debian (9 or later)
- Fedora (35 or later) (Fedora 40 may require a downgrade of its default OpenSSl version)
- CentOS (Stream 8 or later)
Additionally, the following are supported for x64/AMD64-based devices:
- Arch Linux
- ThinPro
- NixOS
- Gentoo
Prerequisites
- A Twingate account with the necessary permissions to create and manage Services. See the Services documentation for more information on how to create a Service account and Service Keys.
Working with the Linux Client in systemd
Installation & configuration
- The Linux Client is installed by following the existing installation process.
- Configure the Linux Client in headless mode by running the
twingate setup
command with the--headless
parameter.
For example:
curl https://binaries.twingate.com/client/linux/install.sh | sudo bashsudo twingate setup --headless /path/to/service_key.json
Additional command line parameters, including the ability to set the default log level, are available. More information is available by running twingate help setup
.
Starting & stopping the Client
# Start the clientsudo twingate start
# Check client statustwingate status
# Stop the clientsudo twingate stop
Troubleshooting
The Linux Client runs as a systemd
service with logs retrievable via journalctl
.
# Retrieve recent client logssudo journalctl -u twingate --since "1 hour ago"
Working with the Linux Client in Docker
The Linux Client may also be run in a Docker container. This may be useful in situations where only an individual service requires access to Twingate protected Resources.
Prior to running the Docker container, ensure that the Service Key is available on the host system. The Service Key should be mounted into the container using a volume.
Host Network Access in Headless Mode
The examples below assume other services or applications that need to access private, protected Resources are running in the same Docker network as the Client. If you need the Client to run in headless mode within a Docker container and capture all network traffic across all interfaces, including the host’s, you can use the --network host
option in a docker run command or add network_mode: host
to the service definition in your Docker Compose file.
Running the Client in Docker
The command below will run the Twingate Client in a Docker container, mounting the Service Key from the host system and starting the Client in headless mode. The command can be modified to suit the specific requirements of the environment, but the following parameters are required:
device /dev/net/tun
cap-add NET_ADMIN
Without these two parameters the Client running inside of the container will not be able to connect to Twingate.
Unsupported Compute Engines
Compute engines that do not support adding kernel capabilities to containers, such as AWS Fargate, are not supported at this time.
docker run -d\ -v /path/to/service-key/:/etc/twingate-service-key/ \ --device /dev/net/tun \ --cap-add NET_ADMIN \ ubuntu:latest bash -c " apt-get update && apt-get install curl -y && curl https://binaries.twingate.com/client/linux/install.sh | bash && sudo twingate setup --headless /etc/twingate-service-key/service-key.json && sudo twingate start && sleep infinity "
Alternatively, you can use Docker Compose to manage the container. An example docker-compose.yml
file is shown below:
version: "1.0"
services: tg-headless-client: image: ubuntu:latest command: > bash -c "apt-get update && apt-get install curl -y && curl https://binaries.twingate.com/client/linux/install.sh | bash && sudo twingate setup --headless /etc/twingate-service-key/service-key.json && sudo twingate start && sleep infinity" volumes: - /path/to/service-key/:/etc/twingate-service-key/ devices: - /dev/net/tun cap_add: - NET_ADMIN restart: unless-stopped
Finally, if you are using the Client to support a specific service and want it to only be available for that service, you can use a Compose file to load both containers and tie them together:
version: "1.0"
volumes: uptime-kuma: external: true
services: tg-headless-client: image: ubuntu:latest container_name: tg-headless-client command: > bash -c "apt-get update && apt-get install curl -y && curl https://binaries.twingate.com/client/linux/install.sh | bash && sudo twingate setup --headless /etc/twingate-service-key/service-key.json && sudo twingate start && sleep infinity" volumes: - /path/to/service-key/:/etc/twingate-service-key/ devices: - /dev/net/tun cap_add: - NET_ADMIN ports: - "3001:3001" restart: always uptime-kuma: image: louislam/uptime-kuma:1 container_name: uptime-kuma volumes: - uptime-kuma:/app/data network_mode: "service:tg-headless-client" depends_on: - tg-headless-client restart: always
In this example we are loading the Twingate Client in headless mode and then loading the Uptime Kuma service. Uptime Kuma is a commonly used open-source uptime monitoring and alerting system, and we want it to be able to access Resources in Remote Networks via the Twingate service. The network_mode: "service:tg-headless-client"
line ties the Uptime Kuma service to the Twingate Client service, allowing it to access the network tunnel created by the Client.
Running the Twingate Client in CI/CD Jobs & Workflows
Twingate’s Headless Client can be flexibly integrated into existing CI/CD workflows. In addition to the above examples for systemd
and docker
, the following methods are commonly used by teams to enable private, protected access to Resources.
Using Github Actions
Twingate’s Github Action is a pre-defined step that integrates seamlessly into existing workflows to ensure the runner has access to private Resources (essentially installs as systemd
like the example above).
Self-hosted Runners
Self-hosted runners can use either the systemd
or docker
methods to access Resources that are not directly routable from the runner’s subnet. This provides greater flexibility for private Resource access in CI/CD pipelines.
Containerized Jobs
In some cases, third-party services provide Github Actions or steps that spin up Docker containers on the runner to deploy infrastructure (e.g. via Terraform/Pulumi). Here’s how to ensure these containers can access private Resources through Twingate:
Shared Docker Network: If possible, run the container in the same Docker network as the Twingate Client, where the service in question uses the Twingate Client’s network stack, similar to the Docker Compose setup above.
When Sharing Networks Is Not Possible:
Some services don’t allow multiple containers to share the same network namespace. In these cases, containers will typically use the host’s /etc/resolv.conf
for DNS resolution unless explicitly overridden. This can cause DNS queries for private Resources to fail, as the container doesn’t know to forward DNS queries to the Twingate Client’s local DNS resolvers running on the host.
To ensure containers use Twingate’s DNS and route traffic correctly through Twingate’s tunnel, follow these steps:
- Install the Twingate Client in Headless Mode: Run the Twingate Client in headless mode on the runner’s host (as a systemd service or using the GitHub Action).
- Stop Docker Daemon: Temporarily stop the Docker service to make changes that apply to all containers.
- Update Docker’s DNS Configuration: Add the Twingate Client’s local DNS resolvers (
100.95.0.251
,100.95.0.252
,100.95.0.253
,100.95.0.254
) to Docker’s/etc/docker/daemon.json
. - Restart Docker: Restart Docker to apply the new DNS settings and ensure subsequent containers use Twingate for DNS resolution.
Example:
- name: Configure Docker to Use Twingate DNS run: | # Step 1: Stop Docker service to make changes sudo systemctl stop docker
# Step 2: Create a temporary file to store the updated Docker configuration tmp=$(mktemp)
# Step 3: Add Twingate DNS resolvers to Docker's daemon configuration file sudo jq '. + { "dns": ["100.95.0.251", "100.95.0.252", "100.95.0.253", "100.95.0.254"] }' /etc/docker/daemon.json > "$tmp"
# Step 4: Move the updated configuration back to the Docker daemon file sudo mv "$tmp" /etc/docker/daemon.json
# Step 5: Restart Docker service to apply changes sudo systemctl start docker
# Step 6: Verify Docker is using the updated DNS resolvers docker info | grep "DNS"
Other CI/CD platforms
As long as your CI/CD platform supports installing the Twingate Client in headless mode, allows underlying network configuration, and runs on a supported OS distro, you should be able to tunnel traffic to private Resources with relative success.
Last updated 14 hours ago