A SwiftUI-based iOS application for controlling a personal AWS-hosted OpenVPN server. This app was created during a sabbatical in Taipei as part of a larger project to build a personal VPN service. The entire codebase was generated with the assistance of AI tools (ChatGPT and Claude).
VPNControl is designed to work with a custom AWS infrastructure that includes:
- An EC2 instance running OpenVPN
- API Gateway and Lambda for server control
- Infrastructure defined with Terraform
The app provides a simple interface to:
- Start and stop your VPN instance
- Monitor VPN status in real-time
- Securely store API credentials
- Xcode 15.0 or later
- iOS 16.0 or later
- An AWS infrastructure set up with:
- API Gateway endpoint
- API Key for authentication
- Lambda function for EC2 control
- EC2 instance configured with OpenVPN
- Clone the repository:
git clone git@github.com:rjamestaylor/VPNControl-ios.git-
Create a new Xcode project:
- Create a new iOS app project in Xcode
- Choose "SwiftUI App" as the interface
- Set minimum deployment target to iOS 16.0
- Add the Swift files from this repository to your project
-
Configure the API endpoint:
- Open
VPNApiClient.swift - Replace the
baseURLwith your API Gateway URL:
- Open
private let baseURL = "https://your-api-gateway-url.execute-api.us-east-1.amazonaws.com/Prod"- Build and run the project in Xcode
The app requires an API key for authentication. Once you have your API key from AWS:
- Launch the app
- Go to Settings
- Enter your API key
- The key will be securely stored in the iOS Keychain
The app follows the MVVM (Model-View-ViewModel) pattern:
- Models:
VPNState,StatusInfo - Views:
ContentView,StatusCardView,SettingsView - ViewModels:
VPNViewModel,AppSettings
ContentView.swift: Main interface with VPN controlsStatusCardView.swift: Visual representation of VPN statusSettingsView.swift: API key management
VPNViewModel.swift: Manages VPN state and API interactionsAppSettings.swift: Handles app configuration and API key storage
VPNApiClient.swift: API client for VPN control endpoints- Implements async/await for network calls
- Handles API authentication and error cases
KeychainManager.swift: Secure storage for API credentials- Implements best practices for iOS keychain usage
- API keys stored securely in iOS Keychain
- HTTPS for all API communications
- AWS API Gateway authentication
- No VPN credentials stored in the app
The app uses URLSession with async/await for API calls:
func getStatus() async throws -> [String: Any] {
guard let url = URL(string: "\(baseURL)/vpn/status") else {
throw VPNError.invalidURL
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue(apiKey, forHTTPHeaderField: "x-api-key")
let (data, response) = try await session.data(for: request)
// ... response handling
}VPN state is managed through a state enum with associated UI properties:
enum VPNState: String, Codable {
case running
case stopped
case starting
case stopping
var isTransitioning: Bool {
self == .starting || self == .stopping
}
}Comprehensive error handling for network and keychain operations:
enum VPNError: Error {
case invalidURL
case networkError(Error)
case invalidResponse
case decodingError
}This project demonstrates the potential of AI-assisted development. The entire codebase was generated through conversations with AI tools, with human oversight for:
- Architecture decisions
- Security considerations
- UI/UX choices
- Integration points
The app expects these API endpoints:
- POST
/vpn- Start/Stop VPN instance - GET
/vpn/status- Get VPN status
API requests must include:
x-api-keyheader for authentication- JSON body for POST requests
- Query parameters for GET requests
This project is open for contributions. Please:
- Fork the repository
- Create a feature branch
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenVPN for the VPN server software
- AWS for the cloud infrastructure
- ChatGPT and Claude for code generation assistance
- https://www.appicon.co/#image-sets for quickly creating the image sets from the main PNG
For questions or suggestions, please open an issue in the repository. Or, reference this repo and ask ChatGPT or Claude to resolve your issue. That's the spirit of this project.