This guide walks you through deploying a Vaultody MPC co-signer node on Amazon Web Services (AWS). The whole deployment is automated by a single script — you run it, answer a few prompts, and it hands you back a public IP address. You point your domain at that IP and, a few minutes later, your node is online over HTTPS.
Everything runs on standard AWS services: an EC2 instance behind a fixed Elastic IP, an automatically issued and renewed Let's Encrypt TLS certificate, your credentials in AWS Secrets Manager, and the node's database in an Amazon S3 bucket.
The script requires the AWS command-line tool to interact with AWS.
Installation:
macOS:
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
Linux:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip && sudo ./aws/install
Windows: Download the MSI from https://aws.amazon.com/cli/
Verify installation:
aws --version
Linux/macOS: Built-in (works with the macOS default bash 3.2 and newer)
Windows: Use Git Bash, WSL, or AWS CloudShell
Required for generating cryptographic keys for your MPC node. Usually pre-installed on Linux/macOS.
Verify installation:
openssl version
Used by the script to parse AWS responses.
jq --version
# macOS: brew install jq · Debian/Ubuntu: sudo apt-get install jq
An active AWS account
An IAM user (or role) you can authenticate as
Authenticate with AWS before running the script. The simplest method:
aws configure
# Enter: Access Key ID, Secret Access Key, default region (e.g. eu-central-1), output format (json)
For SSO / IAM Identity Center: aws configure sso then aws sso login.
Verify identity (should print your account and user, not an error):
aws sts get-caller-identity
A valid payment method must be on the account. Resources incur charges as soon as they are created, so set a budget alert (AWS Budgets) before deploying.
Your IAM principal needs to create the resources. The simplest path is an administrator. The least-privilege policy is:
{
"Version": "2012-10-17",
"Statement": [
{ "Sid": "ComputeAndNetworking", "Effect": "Allow",
"Action": ["ec2:*", "autoscaling:*", "ssm:GetParameter"], "Resource": "*" },
{ "Sid": "SecretsManager", "Effect": "Allow",
"Action": ["secretsmanager:CreateSecret","secretsmanager:PutSecretValue","secretsmanager:DescribeSecret","secretsmanager:GetSecretValue"],
"Resource": "*" },
{ "Sid": "S3Bucket", "Effect": "Allow",
"Action": ["s3:CreateBucket","s3:ListBucket","s3:ListAllMyBuckets","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:PutBucketPublicAccessBlock","s3:PutBucketVersioning","s3:PutEncryptionConfiguration","s3:PutBucketEncryption"],
"Resource": ["arn:aws:s3:::vaultody-co-signer-artifacts-*","arn:aws:s3:::vaultody-co-signer-artifacts-*/*"] },
{ "Sid": "IAMForInstanceRole", "Effect": "Allow",
"Action": ["iam:CreateRole","iam:GetRole","iam:PutRolePolicy","iam:AttachRolePolicy","iam:CreateInstanceProfile","iam:GetInstanceProfile","iam:AddRoleToInstanceProfile","iam:PassRole"],
"Resource": "*" }
]
}
Format: region (e.g., eu-central-1)
Recommendation: Choose a European region for optimal performance.
Vaultody's central services are hosted in Europe, so a European region minimizes latency and improves MPC protocol communication. Recommended:
eu-central-1 (Frankfurt)
eu-west-1 (Ireland)
You choose only a region — the script automatically picks the Availability Zones inside it. List regions with:
aws ec2 describe-regions --query 'Regions[].RegionName' --output table
Important: AWS supports AMD SEV-SNP confidential computing, offering per-instance memory encryption plus attestation on top of the always-on encryption that Nitro instances already provide. It is available only on m6a / c6a / r6a instance families and only in certain regions.
Pricing: SEV-SNP adds roughly 10% to the On-Demand hourly rate.
Availability: confirm before selecting it:
aws ec2 describe-instance-types --region eu-central-1 \
--filters Name=processor-info.supported-features,Values=amd-sev-snp \
--query 'InstanceTypes[].InstanceType' --output text
If this returns nothing for your region, pick a region that supports it (e.g. eu-west-1) or deploy on a standard instance.
After deployment, verify it is active:
aws ec2 describe-instances --instance-ids i-XXXX \
--query 'Reservations[].Instances[].CpuOptions' --output json
# AmdSevSnp should read "enabled"
Default recommendations:
Without Confidential VM: m6i.large (2 vCPUs, 8 GB RAM)
With Confidential VM: m6a.large (2 vCPUs, 8 GB RAM)
SEV-SNP compatible types: m6a.large, m6a.xlarge, c6a.large, c6a.xlarge, r6a.large, r6a.xlarge
For most deployments, m6i.large / m6a.large provides adequate performance for MPC operations.
AWS has no "project" object. Instead you choose a short prefix used to name and tag every resource (security group, launch template, ASG, secret, IAM role).
Format: lowercase letters, digits and hyphens; 4–30 characters.
Example: mpc-co-signer (default), vaultody-mpc-node-01
Press Enter to accept the default mpc-co-signer.
Format: Fully qualified domain name (FQDN) that you own
Example: mpc-node.yourdomain.com, cosigner.example.com
Requirements:
You must be able to configure DNS records for this domain
The domain is used for the TLS certificate
The domain must be reachable from the internet
After deployment, the script prints an IP address (a fixed Elastic IP). Create a single A record pointing your domain to this IP:
Steps:
Log in to your DNS provider (Route 53, Cloudflare, GoDaddy, Namecheap, DuckDNS, …)
Navigate to DNS management
Add a new A record:
Name/Host: your subdomain (e.g. mpc-node) or the full domain
Type: A
Value/Points to: the IP address from the script output
TTL: 300 seconds (or default)
Save the record
Any DNS provider works — the node validates its certificate by itself, so you never need a special validation (CNAME/TXT) record.
DNS propagation: typically 5–30 minutes.
Verify DNS:
nslookup mpc-node.yourdomain.com
# or
dig mpc-node.yourdomain.com +short
Purpose: Encrypts and secures the local database on your node, which holds MPC key material and state.
Requirements:
Minimum 12 characters
Uppercase, lowercase and numbers (special characters recommended)
Example: MySecurePass123!
Important:
Store it securely (password manager / vault)
Do not share it
You'll need it to manually access or recover the database
Generate a strong password:
openssl rand -base64 20
Purpose: Your node's private key for secure MPC communication. Each co-signer node must have a unique key pair.
# Generate private key in DER format (binary)
openssl ecparam -name prime256v1 -genkey -noout -out private_key.der -outform DER
# Extract public key from private key
openssl ec -in private_key.der -inform DER -pubout -out public_key.der -outform DER
# Convert private key to Base64 for script input
openssl base64 -A -in private_key.der
# Convert public key to Base64 for web portal
openssl base64 -A -in public_key.der
Usage:
Private key (Base64): paste into the deployment script when prompted (it is stored in AWS Secrets Manager)
Public key (Base64): upload to the Vaultody web portal when configuring your node
Key management:
Never share your private key or commit it to version control
Keep a secure backup of both keys
File cleanup:
# After copying the keys, securely delete the files
shred -vfz -n 10 private_key.der public_key.der # Linux
rm -P private_key.der public_key.der # macOS
Purpose: These credentials authenticate your co-signer node with Vaultody's MPC infrastructure.
How to obtain:
Log in to the Vaultody web portal
Navigate to MPC Node Configuration
Create a new co-signer node configuration (upload your public key from input 7)
Copy the generated API Key and API Secret
Important:
These are provided by Vaultody, not generated by you
Each co-signer node has unique credentials
They are stored in Secrets Manager alongside your password and private key
The script uses an Amazon S3 bucket as the persistent storage backend for your MPC co-signer database. This is critical for the following reasons:
Data Persistence: if the EC2 instance is replaced, the MPC database (key shares + state) survives in the bucket
Durability: S3 Standard offers 99.999999999% (11 nines) durability
Disaster Recovery: your key material survives instance failures and accidental overwrites (versioning is enabled)
The deployment script:
Creates an S3 bucket named vaultody-co-signer-artifacts-TIMESTAMP
Blocks all public access, enables versioning and default encryption
Configures the co-signer container to use s3://bucket-name as its database source
Important: the bucket persists even after running the cleanup script. This is intentional, to prevent accidental loss of MPC key material.
# List your MPC buckets
aws s3 ls | grep vaultody-co-signer-artifacts
# List bucket contents
aws s3 ls s3://vaultody-co-signer-artifacts-TIMESTAMP --recursive
# Check storage usage
aws s3 ls s3://vaultody-co-signer-artifacts-TIMESTAMP --recursive --summarize | tail -2
⚠️ WARNING: Only delete the bucket if you are completely certain you want to permanently destroy your MPC key material. This is irreversible.
aws s3 rb s3://vaultody-co-signer-artifacts-TIMESTAMP --force
When to delete: permanently decommissioning the node, or a full teardown of a test environment. When NOT to delete: just cleaning up compute, or planning to redeploy.
After the script completes successfully, you'll see output similar to:
✅ Infrastructure created successfully!
IP Address: 63.182.116.15
Endpoint URL: https://mpc-node.yourdomain.com
📋 NEXT STEPS:
1. Create a DNS A record: mpc-node.yourdomain.com → 63.182.116.15
2. Wait a few minutes for the TLS certificate to be issued automatically.
3. Test the endpoint: curl https://mpc-node.yourdomain.com/health/readiness
As explained in the "Domain Name" section above, create an A record pointing your domain to the provided IP address.
Quick reference:
Type: A
Name: mpc-node (or full domain)
Value: 63.182.116.15 (your IP from the script output)
TTL: 300
The node obtains a Let's Encrypt certificate automatically — there is nothing to provision by hand. Once your domain's A record resolves to the IP, the node fetches and installs the certificate on its own (and renews it automatically thereafter).
Typical timeline: a few minutes after the DNS record is live. The node keeps retrying until the domain resolves, so order doesn't matter.
If you briefly see a certificate warning right after deployment, just wait and retry — it resolves itself once DNS has propagated.
# Liveness (succeeds whenever the container is running)
curl https://mpc-node.yourdomain.com/health/liveness
# Readiness (succeeds when the node is fully operational)
curl https://mpc-node.yourdomain.com/health/readiness
# Expected response:
{"status":"healthy"}
Troubleshooting endpoint issues — no SSH key is needed; connect with AWS Systems Manager:
# Find the instance id
aws ec2 describe-instances --region YOUR_REGION \
--filters "Name=tag:Name,Values=mpc-co-signer" "Name=instance-state-name,Values=running" \
--query 'Reservations[].Instances[].InstanceId' --output text
# View the boot log
aws ec2 get-console-output --instance-id i-XXXX --output text
# Open a shell on the instance
aws ssm start-session --target i-XXXX
Once inside the instance:
docker ps -a # 'mpc-co-signer' and 'caddy' should be Up
docker logs mpc-co-signer
curl http://localhost:8000/health/readiness
Both the deployment and cleanup scripts are idempotent — safe to run repeatedly:
Deployment script behavior:
Checks if each resource exists before creating it
Reuses existing resources (Elastic IP, bucket, IAM role, security group)
Updates the secret with new values if it exists
Recreates the launch template and rolls the instance to pick up changes
Benefits:
Resume after failure: if the script fails partway (network, quota, capacity), just run it again
Update configuration: change credentials or settings by re-running with new values
No duplicate resources: won't create duplicate security groups, IPs, etc.
The cleanup_mpc_resources_aws.sh script removes the disposable infrastructure while preserving critical data.
Testing different deployment configurations
Removing infrastructure due to cost concerns
Troubleshooting deployment issues
Migrating to a different region
./cleanup_mpc_resources_aws.sh
It asks for the region and resource prefix, then interactively confirms what to remove.
Delete secret? [y/N]:
Recommendation: Press N (or just Enter). You'll need the same credentials if you redeploy, and the secret costs almost nothing.
AWS difference: secret deletion uses a 7-day recovery window (recoverable) rather than being immediate.
Delete IAM role + instance profile? [y/N]:
Recommendation: Press N. It is reused on redeploy and incurs no cost.
✅ Always deleted:
Auto Scaling Group and its instance
Launch template
Instance security group
❌ Never deleted automatically:
S3 Bucket (contains your MPC database / key material)
Elastic IP (kept so your DNS A record stays valid)
⚙️ Optionally deleted:
Secret (if you choose to)
IAM role + instance profile (if you choose to)
Redeploy by running the deployment script again. If you kept the secret, IAM role, bucket and Elastic IP (recommended), redeploy is faster and your DNS stays valid.
The bucket must be deleted manually (it holds key material):
aws s3 ls | grep vaultody-co-signer-artifacts
aws s3 ls s3://vaultody-co-signer-artifacts-TIMESTAMP --recursive # verify contents
aws s3 rb s3://vaultody-co-signer-artifacts-TIMESTAMP --force # ⚠️ PERMANENT
Estimated monthly cost for the co-signer infrastructure (eu-central-1, approximate):
Notes:
Confidential VM (SEV-SNP) adds ~10% to the instance cost
Larger instance types increase compute cost
An Elastic IP is free while associated with a running instance (small charge only if left unused)
Reserved Instances / Savings Plans reduce compute cost for 1–3 year commitments
Set an AWS Budgets alert to monitor spend
1. Instance Capacity Unavailable
InsufficientInstanceCapacity
Solution: try a different AZ/region, a different instance type, or retry later.
2. SEV-SNP Not Available in the Region describe-instance-types returns nothing for SEV-SNP. Solution: choose a supported region (e.g. eu-west-1) or deploy a standard instance.
3. Certificate / HTTPS Not Working Solution: confirm your DNS A record points to the exact IP the script printed (dig +short yourdomain.com). Allow a few minutes after the DNS change; the node keeps retrying.
4. Readiness Returns 503 / "unhealthy" The response lists each component. If:
the S3 component is unhealthy → the instance can't reach the bucket (rare; usually self-heals on next boot)
the AMQP component is unhealthy → your API key/secret are wrong, or the node isn't registered yet in the Vaultody portal. Re-check inputs 8.
5. Permission Denied Errors
User is not authorized to perform: <action>
Solution: ensure your principal has the IAM permissions listed in Account Setup.
Key Management:
Store private keys securely (password manager / HSM); never commit to version control
Rotate credentials periodically
Access Control:
Use a dedicated, least-privilege instance role; avoid admin roles on the instance
Enable MFA on your AWS account; prefer IAM Identity Center / SSO
Restrict who can access the account and the Secrets Manager secret
Network Security:
The instance exposes only 80 (certificate challenge + redirect) and 443 (HTTPS)
Prefer SSM Session Manager over SSH (no inbound 22, no key pairs to manage)
Data Protection:
S3 default encryption and Block Public Access are enabled by the script
S3 versioning is enabled so accidental overwrites of MPC state are recoverable
Consider SEV-SNP for memory encryption + attestation
Monitoring:
Enable CloudTrail (account audit log)
Add CloudWatch alarms on instance status
Forward container logs to CloudWatch Logs
Verify in the Vaultody Portal: confirm your node is registered and online, and check its health/status.
Test MPC Operations: run a test signing operation and confirm the co-signer participates correctly.
Set Up Monitoring: CloudWatch alarms and uptime checks.
Document Your Deployment: record region, instance type, domain, bucket name, secret ARN, and your public key.
Vaultody Documentation: contact Vaultody support for platform-specific docs
AWS Documentation: https://docs.aws.amazon.com
Script Issues: check the boot log (aws ec2 get-console-output) and container logs (docker logs mpc-co-signer)
Version: 1.2.0 Last Updated: 2026-06-17