openfortivpn

Written by

in

Fortinet VPN with Docker: Setup Guide

Overview of Architecture

  • openfortivpn-webview (Host): Electron app that opens Microsoft SAML/SSO login, handles MFA, and captures the SVPNCOOKIE.
  • openfortivpn (Docker): Lightweight ubuntu container that creates the actual ppp0 VPN network tunnel using the captured cookie.

Step 1: Directory Structure

Set up your workspace with the following file structure:

fortinet-docker-vpn/
├── Dockerfile.alpine
├── Dockerfile.ubuntu
├── config
├── openfortivpn-connect.sh
└── openfortivpn-webview/   (Cloned automatically by script)

Dockerfile.ubuntu

FROM ubuntu:latest

# Update repositories and install dependencies using apt
RUN apt-get update && apt-get install -y \
    openfortivpn \
    ppp \
    ca-certificates \
    iproute2 \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /home/admin/docker/openfortivpn

COPY config /home/admin/docker/openfortivpn/config

ENTRYPOINT ["openfortivpn", "-c", "/home/admin/docker/openfortivpn/config"]

Dockerfile.alpine

FROM alpine:latest

# Install openfortivpn and network dependencies
RUN apk add --no-cache \
     --repository=https://dl-cdn.alpinelinux.org/alpine/edge/testing \
    --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \
    --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main \
    openfortivpn ppp ca-certificates iproute2

WORKDIR /home/admin/docker/openfortivpn
# Copy config into container
COPY config /home/admin/docker/openfortivpn/config

# Launch openfortivpn using local config
ENTRYPOINT ["openfortivpn", "-c", "/home/admin/docker/openfortivpn/config"]

Step 2: Create Configuration Files

File 1: config

Create a file named config in your project folder:

# Fortinet Gateway Address & Port
host = vpn.dawsoncollege.qc.ca
port = 10443
username = username@dawaoncollege.qc.ca #email
#Password = # Optional
# (Optional) Insert trusted certificate hash if prompted by gateway:
# trusted-cert = 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

Step 3: Create the Master Automation Script (openfortivpn-connect.sh

#!/bin/bash
set -e
#set -x

# Work strictly relative to script location
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"

VPN_HOST="vpn.dawsoncollege.qc.ca:10443"
#IMAGE_NAME="fortinet-vpn"
#WEBVIEW_DIR="/home/admin/docker/openfortivpn/openfortivpn-webview/openfortivpn-webview-electron"
WEBVIEW_DIR="$SCRIPT_DIR/openfortivpn-webview/openfortivpn-webview-electron"

# 0. Distro Selection (Interactive prompt if no argument provided)
CHOICE="$1"

if [ -z "$CHOICE" ]; then
  echo "=========================================="
  echo " Select Docker Distro Image"
  echo " REMEMBER TO CLOSE THE BROWSER WINDOW "
  echo " TO CONTINUE WITH THE SCRIPT PROCESS "
  echo "=========================================="
  PS3="Please enter your choice (1-2): "
  options=("alpine" "ubuntu")
  select opt in "${options[@]}"; do
    case $opt in
      "alpine"|"ubuntu")
        CHOICE="$opt"
        break
        ;;
      *)
        echo "Invalid option $REPLY. Please choose 1 or 2."
        ;;
    esac
  done
  echo ""
fi

case "$CHOICE" in
  alpine)
    DOCKERFILE="Dockerfile.alpine"
    IMAGE_NAME="fortinet-vpn:alpine"
    ;;
  ubuntu)
    DOCKERFILE="Dockerfile.ubuntu"
    IMAGE_NAME="fortinet-vpn:ubuntu"
    ;;
  *)
    echo "Error: Unknown target distro '$CHOICE'. Use 'alpine' or 'ubuntu'."
    exit 1
    ;;
esac

# 0. Distro Selection (Defaults to 'alpine', accepts 'ubuntu' as argument: ./openfortivpn-connect.sh ubuntu)
#CHOICE="${1:-alpine}"

#case "$CHOICE" in
#  alpine)
#    DOCKERFILE="Dockerfile.alpine"
#    IMAGE_NAME="fortinet-vpn:alpine"
#    ;;
#  ubuntu)
#    DOCKERFILE="Dockerfile.ubuntu"
#    IMAGE_NAME="fortinet-vpn:ubuntu"
#    ;;
#  *)
#    echo "Error: Unknown target distro '$CHOICE'. Use 'alpine' or 'ubuntu'."
#    exit 1
#    ;;
#esac

echo "=========================================="
echo "    Fortinet SSO VPN Automated Launcher    "
echo "=========================================="

# 1. Verify Prerequisites
echo "[1/4] Checking host dependencies..."
for cmd in docker node npm git; do
  if ! command -v $cmd &> /dev/null; then
    echo "Error: '$cmd' is not installed. Please install it first."
    exit 1
  fi
done

# Check PPP device
if [ ! -e /dev/ppp ]; then
  echo "Setting up /dev/ppp..."
  sudo mknod /dev/ppp c 108 0 2>/dev/null || true
  sudo chmod 666 /dev/ppp 2>/dev/null || true
fi

# 2. Check/Build Docker Image
echo "[2/4] Checking Docker image '$IMAGE_NAME' (using $DOCKERFILE)..."
if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
  echo "Docker image not found. Building $IMAGE_NAME from $SCRIPT_DIR..."
  
  if [ ! -f "$SCRIPT_DIR/$DOCKERFILE" ] || [ ! -f "$SCRIPT_DIR/config" ]; then
    echo "Error: Missing '$DOCKERFILE' or 'config' in $SCRIPT_DIR."
    exit 1
  fi
#/home/admin/docker/openfortivpn
  docker build -f "$SCRIPT_DIR/$DOCKERFILE" -t "$IMAGE_NAME" "$SCRIPT_DIR"
else
  echo "Docker image '$IMAGE_NAME' is ready."
fi

# 3. Setup openfortivpn-webview
echo "[3/4] Preparing SAML authenticator..."
if [ ! -d "$WEBVIEW_DIR" ]; then
  echo "Cloning openfortivpn-webview repository..."
  git clone https://github.com/gm-vm/openfortivpn-webview.git "$WEBVIEW_DIR"
  cd "$WEBVIEW_DIR"
  npm install
  cd ..
else
  # Ensure dependencies are installed
  if [ ! -d "$WEBVIEW_DIR/node_modules" ]; then
    echo "Installing webview dependencies..."
    cd "$WEBVIEW_DIR"
    npm install
    cd ..
  fi
fi

# 4. Authenticate & Extract Cookie
echo "[4/4] Launching SSO Browser window. Please log in..."
cd "$WEBVIEW_DIR"

# Capture webview output to isolate the SVPNCOOKIE value
RAW_COOKIE=$(npx electron . "$VPN_HOST" --keep-open 2>&1 | grep -oP 'SVPNCOOKIE=\K[^\s]+' | tail -n 1)

cd ..

if [ -z "$RAW_COOKIE" ]; then
  echo "Error: Failed to capture SVPNCOOKIE. Did authentication complete?"
  exit 1
fi

echo ""
echo "=========================================="
echo " Authentication successful!"
echo " Starting VPN Tunnel..."
echo " Press Ctrl+C to disconnect."
echo "=========================================="
echo ""

# 5. Launch Docker VPN
docker run --rm -it \
  --cap-add=NET_ADMIN \
  --device=/dev/ppp \
  --net=host \
  "$IMAGE_NAME" --cookie="$RAW_COOKIE"

Make it executable once:

chmod +x openproxyvpn-connect.sh

Step 4: Daily Operational Commands

Connect

./openfortivpn.sh

Disconnect

Press Ctrl + C in the terminal running the script.

Reset Stale/Saved SSO Sessions (Force Fresh Login)

If you get stuck on “Already Logged In” or need to switch accounts, clear Electron’s session cache:

# On Linux:
rm -rf ~/.config/openfortivpn-webview

# On macOS:
rm -rf ~/Library/Application\ Support/openfortivpn-webview