Created
December 5, 2025 20:04
-
-
Save timching/367245bcfebd5ca5903b9766877d92f9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| FROM ubuntu:22.04 | |
| ENV DEBIAN_FRONTEND=noninteractive \ | |
| LANG=C.UTF-8 | |
| # Install toolset | |
| RUN apt-get update \ | |
| && apt-get install -y --no-install-recommends \ | |
| iproute2 iputils-ping curl ca-certificates bash procps iptables dnsutils \ | |
| && rm -rf /var/lib/apt/lists/* | |
| RUN curl -fsSL https://tailscale.com/install.sh | sh | |
| # Create a single-entrypoint script inside the image (no extra files required) | |
| RUN mkdir -p /usr/local/bin \ | |
| && tee /usr/local/bin/entrypoint.sh > /dev/null <<'EOF' | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| if [ "$AUTO_START" = "1" ]; then | |
| tailscaled >/var/log/tailscaled.log 2>&1 & | |
| fi | |
| # Exec the requested command (default: bash). Network namespace is shared with the running openvpn process. | |
| exec "$@" | |
| EOF | |
| RUN chmod +x /usr/local/bin/entrypoint.sh | |
| ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] | |
| CMD ["bash"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| FROM ubuntu:22.04 | |
| ENV DEBIAN_FRONTEND=noninteractive \ | |
| LANG=C.UTF-8 | |
| # Install OpenVPN and small toolset | |
| RUN apt-get update \ | |
| && apt-get install -y --no-install-recommends \ | |
| openvpn iproute2 iputils-ping curl ca-certificates bash procps iptables dnsutils \ | |
| && rm -rf /var/lib/apt/lists/* | |
| WORKDIR /etc/openvpn | |
| # Create a single-entrypoint script inside the image (no extra files required) | |
| RUN mkdir -p /usr/local/bin \ | |
| && tee /usr/local/bin/entrypoint.sh > /dev/null <<'EOF' | |
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # Configurable paths (you typically mount your .ovpn into /etc/openvpn/client.ovpn) | |
| OVPN_CONF="${OVPN_CONF:-/etc/openvpn/client.ovpn}" | |
| OVPN_CREDS="${OVPN_CREDS:-/etc/openvpn/creds.txt}" | |
| AUTO_START="${AUTO_START:-1}" | |
| clean_up() { | |
| if [ -n "${OPENVPN_PID:-}" ] && kill -0 "$OPENVPN_PID" 2>/dev/null; then | |
| echo "Stopping OpenVPN (pid $OPENVPN_PID)..." | |
| kill "$OPENVPN_PID" || true | |
| wait "$OPENVPN_PID" 2>/dev/null || true | |
| fi | |
| } | |
| trap clean_up EXIT | |
| # If no config present, just drop to the requested shell/command | |
| if [ ! -f "$OVPN_CONF" ]; then | |
| echo "No OpenVPN config found at $OVPN_CONF." | |
| echo "Mount your .ovpn at /etc/openvpn/client.ovpn or set OVPN_CONF." | |
| echo "Starting the container WITHOUT a VPN." | |
| exec "$@" | |
| fi | |
| # If a creds file exists, tighten perms | |
| if [ -f "$OVPN_CREDS" ]; then | |
| chmod 600 "$OVPN_CREDS" || true | |
| fi | |
| if [ "$AUTO_START" = "1" ]; then | |
| echo "Starting OpenVPN using: $OVPN_CONF" | |
| # start OpenVPN in background so we can provide a shell in the same network namespace | |
| openvpn --config "$OVPN_CONF" --auth-nocache --verb 3 & | |
| OPENVPN_PID=$! | |
| # wait for tun interface to appear (timeout 20s) | |
| i=0 | |
| until ip addr show dev tun0 >/dev/null 2>&1 || [ $i -ge 40 ]; do | |
| sleep 0.5 | |
| i=$((i+1)) | |
| done | |
| if ip addr show dev tun0 >/dev/null 2>&1; then | |
| echo "tun0 is up." | |
| else | |
| echo "Warning: tun0 did not appear within timeout. OpenVPN may have failed." | |
| echo "Check logs with: docker logs <container> (or run without -d to see logs)." | |
| fi | |
| fi | |
| # Exec the requested command (default: bash). Network namespace is shared with the running openvpn process. | |
| exec "$@" | |
| EOF | |
| RUN chmod +x /usr/local/bin/entrypoint.sh | |
| # Default to interactive bash so `docker run -it` gives you a shell | |
| ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] | |
| CMD ["bash"] |
Author
Author
bwt you can use docker compose with tailscale's official image https://tailscale.com/kb/1282/docker#code-examples
it's just my use case prefer docker image only :p
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
just a vibe coding script helps me
also saw this similar redit post https://www.reddit.com/r/docker/comments/1dritn0/can_devnettun_be_used_by_multiple_docker/
execute examples
docker run --rm -it --cap-add=NET_ADMIN --device /dev/net/tun -e AUTO_START=1 tailscale-shell docker run --rm -it --cap-add=NET_ADMIN --device /dev/net/tun -v $(pwd)/vpn:/etc/openvpn:ro -e AUTO_START=1 vpn-shelland in mac seems sometimes sucks & buggy dunno why (maybe used same
/dev/net/tun? read more, see diagrams)https://www.reddit.com/r/docker/comments/n3a0eh/kernel_modules_and_docker_for_mac/
but not yet well tested in mac & ubuntu