Building a Cloud-Based Remote Workstation with Secure VPN Tunnel using Terraform and Azure


Project Overview
In this hands-on project, we’ll be provisioning a secure, remote-accessible Ubuntu Linux workstation on Microsoft Azure using Terraform. The VM will have a full graphical desktop interface environment (XFCE) accessible via Remote Desktop Protocol (RDP), because normally we know we can only SSH into a Linux VM but here we will create a desktop environment for our Linux VM , and we’ll secure external access using OpenVPN.
Instead of using automation-heavy scripts, this project focuses on doing things step-by-step — perfect for beginners or anyone looking to truly understand what’s happening under the hood. We'll deploy our infrastructure using Infrastructure as Code (IaC), configure the environment manually, and wrap it all up with a working .ovpn profile that lets you tunnel in securely from your phone or PC.
Project Goals
Provision a Linux virtual machine on Azure using Terraform
Manually install and configure XRDP for remote GUI access for our Linux VM
Set up OpenVPN using a trusted community script from the legendary Angristan real name: Stanislas Piquette on GitHub
Secure traffic from client to VM using a VPN tunnel
Push all Terraform code to GitHub as a portfolio project
Document every step for clarity and learning and upload to Hashnode with Screenshots.
Prerequisites
Please note that to follow along or replicate this project, here’s what you’ll need:
System Requirements a Windows or Linux machine with:
i. VS Code installed
ii. PowerShell, Git Bash, or a terminal of your choice
iii. An SSH key pair (id_rsa and id_rsa.pub)
iv. OpenVPN client installed, downloaded from official website. (for testing .ovpn file)
2 Cloud Access
i. A valid and active Azure account with a free or pay-as-you-go subscription
ii. Azure CLI installed and logged in (az login)
3 Dev Tools
i. Terraform CLI installed
ii. Git installed and connected to your GitHub account (for pushing code)
A Note About the Code Source
All the Terraform code I’m using in this project was generated with the help of ChatGPT. I collaborated with it to create the necessary infrastructure code, security rules, and automation script — all tailored to my learning level as a Junior DevOps Engineer.
Instead of using random templates, I made sure each line of the code was understood, explained, and tweaked to match the goals of this project. This way, I’m not just running code — I’m learning from it.
Lets Get Started.,
Step 1: Uploading and Opening Our Terraform Project in VS Code
The first step in this project is to get our Terraform code into Visual Studio Code (VS Code), where we’ll manage and deploy everything from. Start by creating a folder where all your Terraform scripts will live. For this project, I’ve named my folder " azure-openvpn-xrdp-updated " This name reflects what the project is about: Azure: Cloud provider we’re using, OpenVPN: For securing access, XRDP: For enabling remote GUI, Updated: Because this is the final, cleaned-up version.
Opening the Folder in VS Code
Launch VS Code Click on File → Open Folder Navigate to where we saved or unzipped the folder Select "azure-openvpn-xrdp-updated" and click Open Once we open the folder, VS Code will load all the Terraform files and scripts inside it — including: main.tf
– our infrastructure definition variables.tf
– our input configs outputs.tf
– to display our public IP openvpn-xrdp-setup.sh
–
for post-deployment setup .gitignore
and README.md
– for GitHub integration
In my Terraform project, I’ve broken the code into three key files:
main.tf contains all the cloud resources I want to deploy (VM, network, firewall rules).
variables.tf defines the values I can tweak (region, SSH key path, admin username).
outputs.tf displays helpful info after deployment (like my VM’s public IP). This structure helps me keep things clean, modular, and readable, especially as a beginner learning Infrastructure as Code (IaC) step-by-step.
Step 2: Generate and Add Your Public SSH Key
After we have Opened our Terraform script on VSCODE the next thing we have to do is generate a Public SSH Key which we will have to update the path inside our variables.tf file on VSCODE, so spin up a Windows PowerShell and run the command " ssh-keygen " then follow the onscreen instructions to generate our Public SSH key , once generated successfully we will have to locate the path copy it and update it in our variables.tf file inside the VSCODE, once updated we Press Ctrl + S to save it. Then also we proceed to the main.tf file and update our Azure subscription id on line 3 of the code, then move the curly braces to line 4. then save it.
Please Note: Why We Use Double Backslashes (\) in the SSH Key Path on Windows is because Terraform uses HCL (HashiCorp Configuration Language) so When writing file paths in Terraform (or any code that follows string escaping rules like JSON or HCL), you can't use the regular Windows backslash () by itself, because the backslash is treated as an escape character, it tells the language that a special character is coming next. in essence Terraform might misinterpret \U as a Unicode escape, or . as something invalid which breaks the script.
Step 3: Initialize, Plan, and Deploy Your Terraform Infrastructure
Then we Proceed to the Next step after Saving Our updated configuration, we will open a terminal on VSCODE and login to our Azure account with command "az login" It will open a browser window, and we will Sign in with the Microsoft account tied to our active subscription, Once successful, our terminal will show a list of our Azure subscriptions, then we will run the next command to initialize our terraform codes " terraform init " this command downloads the Azure provider plugin, sets up the .terraform working directory, prepares everything Terraform needs to deploy your infrastructure, after running that we will get a response that " Terraform has been successfully initialized! ".
Proceed to the Next Command, which is " terraform plan -out=tfplan " what this command does is Validates our code, Checks the Azure resources it will deploy and also Saves the result as (tfplan), which we will use in the next step..
After running the second command , we will run the third command which is " terraform apply tfplan " what this command does is to Use the exact plan you saved earlier (tfplan) , Create all Azure resources (VM, VNet, NSG, Public IP, etc.), Provision your secure cloud workstation, once it is successful we will scroll down and copy our Public IP address this will be used to SSH into our VM.
Once we get a successful message with out Public IP for the VM, it shows our deployment is successful, we have just Written Terraform like a pro, Provisioned a fully configured cloud VM, gained access to the public IP of our Virtual Machine. So we verify on the Azure portal if everything is good to go.
Step 4. SSH into the VM and Set a Login Password
We will copy the Public IP address of our VM , then open a Power-Shell Terminal SSH into the VM using this command " ssh azureuser@your-vm-public-ip , then once we are in, we create a password for our VM, reason why we are creating a password is so that once we install the desktop XRDP environment for our VM it requires a username and password for login access the VM on GUI. So we open a PowerShell terminal and run the command " sudo passwd azureuser " to set up a password , where "azureuser" is the username we indicated for our VM in our terraform script.
We have successfully Uploaded and Opening Our Terraform Project in VS Code, Generate and Add our Public SSH Key,Initialize, Plan, and Deploy our Terraform Infrastructure and SSH into the VM and Set a Login Password. this shows we have successfully finished Phase 1 of our project.
PHASE 2. Pushing Our Terraform Code to GitHub, Connect VS Code Project to GitHub, Verify the Push
Step 1. Create a GitHub Repository
After completing Phase 1 (our infrastructure deployment with Terraform), , the next thing on our checklist is to push our Terraform code to GitHub as a portfolio project, we head to GitHub.com , login our credentials then create a New Repository , for this Project our repository will be called " azure-openvpn-xrdp " add a Description , although it is optional Make our Repository Public, no need to check the Readme file box , we already have a readme on our VSCODE, then we create the Repository.
Next we head back to our terminal on VSCODE and run the command " git init " This command initializes a new Git repository in your current folder. It creates a hidden .git/ folder that will track your project’s version history.
Then next we will run the command " git remote add origin https://github.com/stillfreddie/azure-openvpn-xrdp.git " what this command This links our local Git folder to the remote GitHub repository named origin.,
Then run command " git add " This command stages all files in our project folder for commit (including Terraform files, shell script, and README). "
After that run command " git commit -m "Initial commit: Terraform code for Azure OpenVPN + XRDP setup" this creates a commit with a custom message, saving the current version of your code.
Then run this command " git branch -M main " This command renames our local Git branch to main, which is the standard default branch name on GitHub. This ensures our push lands correctly into the expected branch.
Then we run " git push -u origin main" finally to Push our committed files to the main branch of our remote GitHub repository .
Then we head to our GitHub GUI and refresh the newly repository we created , we will find all our codes in there.
Once we verify that our code has successfully been pushed to GitHub, Phase 2 of our project is complete. We now have a working Terraform deployment on Azure, a publicly documented GitHub repo.
Phase 3: XRDP & GUI Setup on the Azure VM
This phase will allow us to remotely access the VM via a graphical interface (like a full Linux desktop) using Remote Desktop Protocol (RDP).
Step 1.
We want to Proceed with our 3rd phase of the project, which is installing and configuring XRDP for a GUI environment for our Linux VM , We SSH into our Linux VM with the Public IP of our Virtual Machine command is SSH azureuser@VMPublicIP .
Step 2. Install and Configure XRDP with XFCE Desktop Environment
Once we are inside the VM there are the commands to run and what the commands will do:
Update
system sudo apt update && sudo apt upgrade -y
Install XFCE desktop environment and XRDP
sudo apt install -y xfce4 xfce4-goodies xrdp
Enable XRDP to start on boot
sudo systemctl enable xrdp
Start XRDP service sudo
systemctl start xrdp
Set XFCE as default for RDP session
echo "startxfce4" > ~/.xsession
Restart XRDP to apply session changes
sudo systemctl restart xrdp
After running all the commands , we Open Remote Desktop Connection on our Windows machine and Paste the public IP of our VM, Click Connect , Username: azureuser and Password, which we created earlier on Powershell. we should now land on a full XFCE desktop interface running in the cloud from right inside our own PC.
Bonus: To Install firefox inside the XRDP GUI we run this command on powershell " sudo apt update && sudo apt install -y firefox " this command will install the latest version of Mozilla Firefox on our VM.
Phase 4. Deploying OpenVPN on Azure via SSH — The Clean, Fast, No-GUI Way
Step 1.
We will SSH into the Azure VM from our local machine with command " ssh azureuser@your-vm-public-ip ".
Next thing to do is to Download the OpenVPN install script, For clarification again, as i Mentioned earlier We’ll be using the famous OpenVPN install script from “Angristan” (aka Stanislas Piquette, the legend behind one of the most trusted OpenVPN server installers on GitHub). to download the Openvpn install script: on our VM we run the command:
' curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh ' " chmod +x openvpn-install.sh " These 2 commands will Downloaded the OpenVPN installer script and make it executable.
Next thing we have to do now is run the next command which is " sudo ./openvpn-install.sh " Then follow the instructions on the screen to fully install the OpenVPN configuration on our VM .
This will start an interactive installer that asks a few questions like:
IP address
Protocol (choose UDP)
Port (default 1194 is fine)
DNS resolver (we picked AdGuard DNS for extra privacy)
Client name (we used techbro)
Whether to enable IPv6 (we selected no)
Whether to password-protect the .ovpn config (we selected no)
You can simply press Enter to accept the default options on most prompts.
Once installation is complete, the script will generate a .ovpn client configuration file like "/home/azureuser/techbro.ovpn
"
This file is what you’ll use to connect to your VPN from any device — PC, phone, tablet, etc.
Step 2: Importing Your OpenVPN Config File (techbro.ovpn)
For easy access, we run the following command on PowerShell to securely copy the .ovpn file from our Azure VM to our local machine: " scp -i C:\Users\fred4.ssh\id_ed25519 azureuser@52.224.237.114:/home/azureuser/techbro.ovpn .
What does this command do? This securely transfers the techbro.ovpn
file from the Azure VM to your current local directory on your PC. After this, you should see the file located here: C:\Users\fred4\techbro.ovpn
. Next Steps: Download and install the OpenVPN Client for Windows from the official site: https://openvpn.net/community-downloads
, then Move the techbro.ovpn file into this folder: C:\Program Files\OpenVPN\config
, we will Launch the OpenVPN GUI from our Start Menu, Right-click the OpenVPN icon in your system tray and click "Connect".
IMPORTANT: Disable DCO to Avoid Connection Issues If you're using OpenVPN 2.6+, you may notice a flood of log messages saying: Data Channel Offload doesn't support DATA_V1 packets. Upgrade your server to 2.4.5 or newer
. This is due to a feature called Data Channel Offload (DCO) that’s not supported by some servers — including the version installed by the Angristan script.
Fix:
Open your .ovpn file (e.g., techbro.ovpn) in Notepad or VS Code and add the following line just after verb 3: disable-dco This disables DCO and ensures a clean, stable VPN connection without error spam. Then save the file and reconnect.
Conclusion
And just like that, we've built a fully provisioned cloud workstation on Azure, Pushed Our code to GitHub, secured it with OpenVPN, and accessed it remotely — all through Infrastructure as Code with Terraform. This project took us from code to cloud, and from command line to secure connection step by step, no shortcuts, no fluff.
Whether you're a DevOps rookie leveling up, or just someone trying to wrap their head around cloud automation, this guide proves that with the right tools, mindset, and community support, you can build and deploy real-world cloud infrastructure from scratch.
Until the next project, stay curious, stay building — and always remember: If it works in your terminal, it works in production. Thank You.
Peace Out.
Subscribe to my newsletter
Read articles from Stillfreddie Techman directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
