Overview
This deployment includes:
- EC2 Instance: ARM64-based t4g.small instance running Ubuntu 22.04
- EBS Storage: 10GB persistent volume for application data
- Built-in Authentication: Uses Oxy’s native authentication with email/password
- Direct Access: No load balancer required, direct access to EC2 instance
Prerequisites
Before starting, ensure you have:
- AWS CLI configured with appropriate permissions
- SSH key pair created in AWS (or create one during setup)
- Basic familiarity with AWS Console and CLI
Step 1: Network Infrastructure Setup
1.1 Create VPC and Subnets
# Create VPC
VPC_ID=$(aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=oxy-simple-vpc}]' \
--query 'Vpc.VpcId' --output text)
# Enable DNS hostnames
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames
# Create Internet Gateway
IGW_ID=$(aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=oxy-simple-igw}]' \
--query 'InternetGateway.InternetGatewayId' --output text)
# Attach Internet Gateway to VPC
aws ec2 attach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID
# Create public subnet
SUBNET_ID=$(aws ec2 create-subnet \
--vpc-id $VPC_ID \
--cidr-block 10.0.1.0/24 \
--availability-zone us-west-2a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=oxy-simple-public-subnet}]' \
--query 'Subnet.SubnetId' --output text)
# Enable auto-assign public IP
aws ec2 modify-subnet-attribute --subnet-id $SUBNET_ID --map-public-ip-on-launch
# Create route table
ROUTE_TABLE_ID=$(aws ec2 create-route-table \
--vpc-id $VPC_ID \
--tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=oxy-simple-public-rt}]' \
--query 'RouteTable.RouteTableId' --output text)
# Add route to Internet Gateway
aws ec2 create-route --route-table-id $ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID
# Associate route table with subnet
aws ec2 associate-route-table --subnet-id $SUBNET_ID --route-table-id $ROUTE_TABLE_ID
1.2 Create Security Group
# Create security group for EC2 instance
EC2_SG_ID=$(aws ec2 create-security-group \
--group-name oxy-simple-sg \
--description "Security group for Oxy EC2 instance with built-in auth" \
--vpc-id $VPC_ID \
--tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=oxy-simple-sg}]' \
--query 'GroupId' --output text)
# Allow SSH access (port 22)
aws ec2 authorize-security-group-ingress \
--group-id $EC2_SG_ID \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0
# Allow HTTP access (port 3000 for Oxy)
aws ec2 authorize-security-group-ingress \
--group-id $EC2_SG_ID \
--protocol tcp \
--port 3000 \
--cidr 0.0.0.0/0
# Allow MCP SSE access (port 8000)
aws ec2 authorize-security-group-ingress \
--group-id $EC2_SG_ID \
--protocol tcp \
--port 8000 \
--cidr 0.0.0.0/0
1.3 Create SSH Key Pair (if needed)
# Create key pair
aws ec2 create-key-pair \
--key-name oxy-simple-keypair \
--query 'KeyMaterial' \
--output text > ~/.ssh/oxy-simple-keypair.pem
# Set proper permissions
chmod 400 ~/.ssh/oxy-simple-keypair.pem
Step 2: Create Configuration Files
2.1 Create Oxy Configuration
Create a local configuration file that will be copied to the server:
cat > config.yml << 'EOF'
databases:
- name: "local_duckdb"
type: "duckdb"
dataset: "/mnt/data/oxy_data/local.db"
models:
- name: "gpt-4"
vendor: "openai"
model_ref: "gpt-4"
key_var: "OPENAI_API_KEY"
authentication:
basic:
smtp_user: "noreply@yourdomain.com"
smtp_password_var: "SMTP_PASSWORD"
smtp_server: "smtp.gmail.com"
smtp_port: 587
defaults:
database: "local_duckdb"
EOF
2.2 Create Environment Variables File
cat > oxy.env << 'EOF'
OXY_STATE_DIR=/mnt/data/oxy_data
AWS_REGION=us-west-2
OPENAI_API_KEY=your_openai_api_key_here
SMTP_PASSWORD=your_smtp_password_here
EOF
2.3 Create Setup Script
cat > oxy-setup.sh << 'EOF'
#!/bin/bash
set -e
# Update system
sudo apt-get update -y
sudo apt-get install -y curl wget unzip
# Mount EBS volume
DEVICE="/dev/nvme1n1"
MOUNT_POINT="/mnt/data"
sudo mkdir -p $MOUNT_POINT
# Check if device exists and format if needed
if [ -b "$DEVICE" ]; then
# Check if filesystem exists
if ! sudo blkid "$DEVICE"; then
echo "Formatting $DEVICE..."
sudo mkfs.ext4 "$DEVICE"
fi
# Mount the device
sudo mount "$DEVICE" "$MOUNT_POINT"
# Add to fstab for persistence
echo "$DEVICE $MOUNT_POINT ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
# Set permissions
sudo chown ubuntu:ubuntu "$MOUNT_POINT"
fi
# Install Oxy
curl --proto '=https' --tlsv1.2 -LsSf https://internal.oxy.tech | sudo bash
# Create directories
mkdir -p /mnt/data/oxy_data
# Copy configuration files (these will be uploaded separately)
# Environment file should be placed at /mnt/data/oxy.env
# Config file should be placed at /mnt/data/config.yml
# Create systemd service
sudo tee /etc/systemd/system/oxy.service << 'SERVICE_EOF'
[Unit]
Description=Oxy Application with Built-in Auth
After=network.target
[Service]
Type=forking
User=ubuntu
WorkingDirectory=/mnt/data
EnvironmentFile=/mnt/data/oxy.env
ExecStart=/bin/bash -c '/usr/local/bin/oxy serve --auth-mode built-in --config /mnt/data/config.yml --port 3000 & /usr/local/bin/oxy mcp-sse --port 8000 & wait'
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
SERVICE_EOF
# Enable service (but don't start yet - wait for config files)
sudo systemctl daemon-reload
sudo systemctl enable oxy
echo "Setup complete. Upload config files and start service manually."
EOF
# Make script executable
chmod +x oxy-setup.sh
Step 3: Launch EC2 Instance
3.1 Get Latest Ubuntu ARM64 AMI
# Get latest Ubuntu 22.04 ARM64 AMI ID
AMI_ID=$(aws ec2 describe-images \
--owners 099720109477 \
--filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-arm64-server-*" \
--query 'Images | sort_by(@, &CreationDate) | [-1].ImageId' \
--output text)
echo "Using AMI: $AMI_ID"
3.2 Launch EC2 Instance
# Encode user data script
USER_DATA=$(base64 -i oxy-setup.sh)
# Launch instance
INSTANCE_ID=$(aws ec2 run-instances \
--image-id $AMI_ID \
--count 1 \
--instance-type t4g.small \
--key-name oxy-simple-keypair \
--security-group-ids $EC2_SG_ID \
--subnet-id $SUBNET_ID \
--user-data "$USER_DATA" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=oxy-simple-instance}]' \
--query 'Instances[0].InstanceId' \
--output text)
echo "Launched instance: $INSTANCE_ID"
# Wait for instance to be running
aws ec2 wait instance-running --instance-ids $INSTANCE_ID
echo "Instance is now running"
3.3 Create and Attach EBS Volume
# Get instance availability zone
AZ=$(aws ec2 describe-instances \
--instance-ids $INSTANCE_ID \
--query 'Reservations[0].Instances[0].Placement.AvailabilityZone' \
--output text)
# Create EBS volume
VOLUME_ID=$(aws ec2 create-volume \
--size 10 \
--availability-zone $AZ \
--volume-type gp3 \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=oxy-simple-data}]' \
--query 'VolumeId' \
--output text)
# Wait for volume to be available
aws ec2 wait volume-available --volume-ids $VOLUME_ID
# Attach volume to instance
aws ec2 attach-volume \
--volume-id $VOLUME_ID \
--instance-id $INSTANCE_ID \
--device /dev/xvdf
echo "Attached volume: $VOLUME_ID"
4.1 Get Instance IP and Connect
# Get the instance public IP
INSTANCE_IP=$(aws ec2 describe-instances \
--instance-ids $INSTANCE_ID \
--query 'Reservations[0].Instances[0].PublicIpAddress' \
--output text)
echo "Instance IP: $INSTANCE_IP"
# Wait a few minutes for the user data script to complete
echo "Waiting for instance setup to complete..."
sleep 300
4.2 Upload Configuration Files
# Upload configuration files
scp -i ~/.ssh/oxy-simple-keypair.pem config.yml ubuntu@$INSTANCE_IP:/tmp/
scp -i ~/.ssh/oxy-simple-keypair.pem oxy.env ubuntu@$INSTANCE_IP:/tmp/
# Connect and move files to correct location
ssh -i ~/.ssh/oxy-simple-keypair.pem ubuntu@$INSTANCE_IP << 'REMOTE_EOF'
# Move config files
sudo mv /tmp/config.yml /mnt/data/
sudo mv /tmp/oxy.env /mnt/data/
sudo chown ubuntu:ubuntu /mnt/data/config.yml /mnt/data/oxy.env
# Start the service
sudo systemctl start oxy
sudo systemctl status oxy
REMOTE_EOF
Step 5: Access Your Oxy Instance
5.1 Access the Application
echo "Access your Oxy application at: http://$INSTANCE_IP:3000"
5.2 First-Time Setup
- Open your browser and navigate to
http://$INSTANCE_IP:3000
- You’ll be prompted to create an admin account
- Enter your email and password to create the first user
- The application will send a verification email (if SMTP is configured)
5.3 Authentication Configuration
With built-in authentication, you can configure:
- Basic Email/Password: Users register with email and password
- SMTP Integration: For email verification and password reset
- Google OAuth (optional): Add Google authentication alongside basic auth
Example configuration in config.yml
:
authentication:
basic:
smtp_user: "noreply@yourdomain.com"
smtp_password_var: "SMTP_PASSWORD"
smtp_server: "smtp.gmail.com"
smtp_port: 587
google: # Optional
client_id: "your-google-client-id"
client_secret_var: "GOOGLE_CLIENT_SECRET"
Step 6: Monitoring and Maintenance
6.1 Check Service Status
# SSH into instance
ssh -i ~/.ssh/oxy-simple-keypair.pem ubuntu@$INSTANCE_IP
# Check service status
sudo systemctl status oxy
sudo journalctl -u oxy -f # Follow logs
# Check disk usage
df -h /mnt/data
6.2 Application Logs
# View application logs
sudo journalctl -u oxy --since "1 hour ago"
# View specific log files if they exist
ls -la /mnt/data/oxy_data/logs/
6.3 Data Backup
# Create manual snapshot
SNAPSHOT_ID=$(aws ec2 create-snapshot \
--volume-id $VOLUME_ID \
--description "Oxy data backup $(date +%Y-%m-%d)" \
--query 'SnapshotId' \
--output text)
echo "Created snapshot: $SNAPSHOT_ID"
Troubleshooting
Common Issues
1. Service fails to start
# Check service logs
sudo journalctl -u oxy -n 50
# Check configuration file syntax
/usr/local/bin/oxy validate --config /mnt/data/config.yml
# Verify environment variables
cat /mnt/data/oxy.env
2. Database connection issues
# Check if DuckDB file exists and permissions
ls -la /mnt/data/oxy_data/
sudo chown -R ubuntu:ubuntu /mnt/data/oxy_data/
3. Cannot access application
# Check if service is running
sudo systemctl status oxy
# Check security group allows port 3000
aws ec2 describe-security-groups --group-ids $EC2_SG_ID
# Test port locally
ssh -i ~/.ssh/oxy-simple-keypair.pem ubuntu@$INSTANCE_IP
curl http://localhost:3000/health
4. Email authentication not working
# Check SMTP configuration
# Test SMTP connection manually
telnet smtp.gmail.com 587
# Verify environment variables are set
grep SMTP /mnt/data/oxy.env
Security Best Practices
- Restrict SSH access: Update security group to only allow SSH from your IP
- Use HTTPS: Set up SSL certificate and nginx proxy for production
- Regular updates: Keep the system and Oxy updated
- Backup strategy: Implement automated EBS snapshots
- Monitor logs: Set up log monitoring and alerting
Scaling Up
When you need more features or scale:
- Add Load Balancer: Implement ALB for high availability
- Database Migration: Move from DuckDB to PostgreSQL or other production database
- Container Migration: Consider moving to the ECS deployment
- Authentication Upgrade: Add SSO or move to managed authentication
Cleanup
To destroy the infrastructure:
# Stop and delete instance
aws ec2 terminate-instances --instance-ids $INSTANCE_ID
# Wait for termination
aws ec2 wait instance-terminated --instance-ids $INSTANCE_ID
# Delete EBS volume
aws ec2 delete-volume --volume-id $VOLUME_ID
# Delete security group
aws ec2 delete-security-group --group-id $EC2_SG_ID
# Delete VPC resources
aws ec2 delete-route --route-table-id $ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0
aws ec2 disassociate-route-table --association-id $(aws ec2 describe-route-tables --route-table-ids $ROUTE_TABLE_ID --query 'RouteTables[0].Associations[0].RouteTableAssociationId' --output text)
aws ec2 delete-route-table --route-table-id $ROUTE_TABLE_ID
aws ec2 delete-subnet --subnet-id $SUBNET_ID
aws ec2 detach-internet-gateway --internet-gateway-id $IGW_ID --vpc-id $VPC_ID
aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID
aws ec2 delete-vpc --vpc-id $VPC_ID
# Delete key pair
aws ec2 delete-key-pair --key-name oxy-simple-keypair
rm ~/.ssh/oxy-simple-keypair.pem
# Clean up local files
rm config.yml oxy.env oxy-setup.sh
Next Steps