DEV Community

Deploy Your Own 24/7 AI Agent on AWS EC2 with Docker & Tailscale (The Secure Way)

No, you don't need a Mac Mini or fancy hardware setup to run your own AI agent 24/7. All you need is a cloud virtual machine or VPS (Virtual Private Server).

I know what you're thinking: "What about security?" And you should be thinking about it. That's exactly why I'm going to walk you through the step-by-step process to securely set up an AI agent running as a Docker container.

Imagine having your own private AI assistant running 24/7 on a cloud server you control-accessible from anywhere, yet completely shielded from the public internet. That's exactly what we're building today.

In this guide, we'll deploy OpenClaw (also known as Moltbot/Clawdbot) on an AWS EC2 instance using Docker containers. But we're not just going to spin up a container and call it a day. We'll harden our server, lock down SSH access, and use Tailscale to create a secure private network that only you can access.

What You'll Have by the End

  • A hardened Ubuntu server with non-standard SSH configuration
  • Docker running OpenClaw in an isolated container
  • Secure private access via Tailscale (no public ports exposed)
  • A fully functional AI assistant accessible from your browser Let's get started.

If you prefer video tutorial, you can watch the below end-to-end video (else, keep reading the blog)

Prerequisites

Before we dive in, make sure you have the following ready:

Cloud Infrastructure

  • AWS Account with EC2 access
  • A fresh Ubuntu 24.04 LTS instance (Recommended specs: 2 vCPU, 4GB RAM, 15GB storage)
  • Key Pair: Your .pem file from AWS (e.g., moltbot.pem) saved on your local computer
  • Current Access: Ability to SSH into the instance as the default ubuntu user

API Keys

  • Anthropic API Key (for Claude Sonnet/Opus - recommended for best performance)
  • OpenAI API Key (Optional, as a backup)

Networking

  • Tailscale Account: Free tier is sufficient (this is how we'll securely access our bot)

Pro Tip: If you're new to AWS, providers like Hetzner, DigitalOcean, or Vultr also work perfectly with this guide.


Phase 1: VM Hardening (Do This FIRST)

Before we install anything fun, we need to secure our server. Think of this as locking the doors and windows before you move your valuables inside.

Step 1: Create a New User

First, SSH into your server as the default ubuntu user:

ssh -i "moltbot.pem" ubuntu@<YOUR-EC2-PUBLIC-IP>
Enter fullscreen mode Exit fullscreen mode

Once connected, let's update the system and create a dedicated user for OpenClaw:

# Update system
sudo apt update && sudo apt upgrade -y

# Create a new user (replace 'openclaw' if you want a different name)
sudo adduser openclaw
# (Enter a strong password when prompted)

# Grant sudo rights
sudo usermod -aG sudo openclaw
Enter fullscreen mode Exit fullscreen mode

Why a new user? Running applications as a dedicated user follows the principle of least privilege. If something goes wrong, the blast radius is contained.

Step 2: Set Up SSH Keys for the New User

Here's where many tutorials fail you. The AWS key (.pem file) only works for the ubuntu user by default. We need to copy the authorized keys to our new user, or we'll be locked out.

Run these commands while still logged in as ubuntu:

# 1. Create the SSH directory for the new user
sudo mkdir -p /home/openclaw/.ssh

# 2. Copy the authorized keys from 'ubuntu' to 'openclaw'
sudo cp /home/ubuntu/.ssh/authorized_keys /home/openclaw/.ssh/

# 3. Fix permissions (CRITICAL: If this is wrong, login will fail)
sudo chown -R openclaw:openclaw /home/openclaw/.ssh
sudo chmod 700 /home/openclaw/.ssh
sudo chmod 600 /home/openclaw/.ssh/authorized_keys
Enter fullscreen mode Exit fullscreen mode

The Permission Trinity: Directory at 700, keys file at 600, owned by the user. Get any of these wrong, and SSH will silently reject your login.

Step 3: Configure AWS Security Group (External Firewall)

Time to switch to your web browser. We need to tell AWS to allow traffic on our new SSH port.

  1. Go to EC2 Dashboard → Security Groups
  2. Select your instance's security group → Edit inbound rules
  3. Add Rule:
    • Type: Custom TCP
    • Port: 2222
    • Source: 0.0.0.0/0 (or "My IP" for extra security)
  4. DO NOT delete the rule for Port 22 yet - this is your safety net
  5. Save rules

Step 4: Configure UFW (Internal Firewall)

Back in your terminal, let's set up the host-level firewall:

# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow the CURRENT port (Safety Net)
sudo ufw allow 22/tcp

# Allow the FUTURE port
sudo ufw allow 2222/tcp

# Enable the firewall
sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

When prompted, type y to confirm. You now have two layers of firewall protection.

Step 5: The Golden Test

This is the moment of truth. Before we disable password authentication or change ports, we need to prove that our new user can log in with the SSH key.

Keep your current terminal window open (this is your lifeline).

Open a NEW terminal window on your local computer and run:

ssh -i "moltbot.pem" openclaw@<YOUR-IP-ADDRESS>
Enter fullscreen mode Exit fullscreen mode
Result Action
Success: You log in without being prompted for a password Proceed to Step 6
Failure: "Permission denied" Go back and re-check Step 2. Do not proceed.

Step 6: Lock Down SSH Configuration

Now that we've verified key-based login works, it's time to harden SSH. This is where Ubuntu 24.04 throws a curveball that catches many admins off guard.

Edit the SSH config file:

sudo vi /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode

Make the following changes:

Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Enter fullscreen mode Exit fullscreen mode

Save and close the file (:wq in vi).

Disable Systemd Socket Activation (CRITICAL)

Here's the gotcha: Ubuntu 24.04 uses "socket activation" which holds Port 22 open regardless of what you put in sshd_config. You must disable this:

# Stop the socket listener
sudo systemctl stop ssh.socket
sudo systemctl disable ssh.socket

# Restart the SSH service to apply your new config
sudo systemctl restart ssh
Enter fullscreen mode Exit fullscreen mode

Verify the Port Change:

sudo ss -tulpn | grep ssh
Enter fullscreen mode Exit fullscreen mode
Output Status
0.0.0.0:2222 Success!
0.0.0.0:22 Something went wrong. Do NOT disconnect.

Step 7: Final Verification & Cleanup

Open a NEW terminal window and test the new port:

ssh -p 2222 -i "moltbot.pem" openclaw@<YOUR-IP-ADDRESS>
Enter fullscreen mode Exit fullscreen mode

Only if that works, go back to your server terminal and lock down Port 22:

sudo ufw delete allow 22/tcp
Enter fullscreen mode Exit fullscreen mode

Then go to AWS Security Groups and delete the inbound rule for Port 22.

Important: From this point forward, you can no longer use "EC2 Instance Connect" (the browser console). You must always use the SSH command above.


Phase 2: Environment Setup

With our server hardened, it's time to install the software stack. We'll set up Docker to run OpenClaw in isolation and Tailscale to create our private access tunnel.

1. Install Docker & Docker Compose

Docker ensures OpenClaw's dependencies don't interfere with your host OS. Here's the official installation method:

# Install Docker dependencies
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y

# Add Docker GPG key & Repository
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y

# Allow 'openclaw' user to run Docker without sudo
sudo usermod -aG docker ${USER}
Enter fullscreen mode Exit fullscreen mode

Now log out and log back in for the group change to take effect:

exit
Enter fullscreen mode Exit fullscreen mode

Then reconnect via SSH:

ssh -p 2222 -i "moltbot.pem" openclaw@<YOUR-IP-ADDRESS>
Enter fullscreen mode Exit fullscreen mode

Verify Docker works without sudo:

docker run hello-world
Enter fullscreen mode Exit fullscreen mode

2. Install Tailscale (The Secure Access Layer)

Here's where the magic happens. Instead of exposing OpenClaw's web port (18789) to the public internet, we'll use Tailscale to create a private mesh network. Only devices on your Tailnet can access the bot.

On your EC2 server:

curl -fsSL https://tailscale.com/install.sh | sh
Enter fullscreen mode Exit fullscreen mode

After installation, authenticate with your Tailscale account:

sudo tailscale up
Enter fullscreen mode Exit fullscreen mode

Follow the link provided to authorize your server.

On your local machine:

Install Tailscale from tailscale.com/download and sign in with the same account.

Once both devices are on your Tailnet, they can communicate securely without any public ports.


Phase 3: OpenClaw Installation

The infrastructure is ready. Let's deploy the bot.

1. Clone the Repository

git clone https://github.com/openclaw/openclaw.git
cd openclaw
Enter fullscreen mode Exit fullscreen mode

2. Clean Up Old Configurations

If you've experimented with OpenClaw before, nuke any old config folders to prevent conflicts:

sudo rm -rf ~/.openclaw
Enter fullscreen mode Exit fullscreen mode

3. Pre-Create the Configuration Folder

This step prevents the dreaded "Permission Denied" errors. We create the folder manually and set permissions so both you AND Docker can write to it:

# Create the folder structure
mkdir -p /home/openclaw/.openclaw/workspace

# Give full read/write access (fixes the "Permission Denied" error)
sudo chmod -R 777 /home/openclaw/.openclaw
sudo chown -R openclaw:openclaw ~/openclaw
sudo chmod -R 775 ~/openclaw
Enter fullscreen mode Exit fullscreen mode

4. Run the Setup Script

Now we're ready for the main event:

cd ~/openclaw
./docker-setup.sh
Enter fullscreen mode Exit fullscreen mode

A series of prompts will appear. Select EXACTLY these options to avoid crashes:

Prompt Selection
Onboarding mode Manual
Setup Local gateway (this machine)
Workspace directory (Press Enter to accept default)
Model/auth Provider Anthropic
Anthropic API Key (Enter your key)
Gateway port 18789
Gateway bind Tailnet
Gateway auth Token
Tailscale exposure Off
Gateway Token (Create a secure token)
Configure chat channel (Whatsapp/Telegram - your choice)
Configure Skills No
Hooks Skip for Now

Critical Warning: Do NOT select "Serve" for Tailscale exposure. This bypasses complex proxy logic that causes crashes. Select "Off" - Tailscale already handles secure access.

Wait for completion. The container will start, but DO NOT LOGIN YET.

5. The "Insecure Auth" Injection

Here's a quirk with OpenClaw: At this stage, the bot is running but will block your browser because you're connecting over HTTP (not HTTPS). Since Tailscale already encrypts our traffic end-to-end, we can safely enable HTTP authentication.

First, install jq inside the container:

docker compose exec -u root openclaw-gateway bash -c "apt update && apt install -y jq"
Enter fullscreen mode Exit fullscreen mode

Then inject the setting:

docker compose exec -T openclaw-gateway bash -c '
jq ".gateway.controlUi.allowInsecureAuth = true" \
/home/node/.openclaw/openclaw.json > /home/node/.openclaw/tmp.json && \
mv /home/node/.openclaw/tmp.json /home/node/.openclaw/openclaw.json'
Enter fullscreen mode Exit fullscreen mode

Restart the bot to apply changes:

docker compose restart
Enter fullscreen mode Exit fullscreen mode

Why is this safe? We're not exposing any ports to the public internet. Traffic flows exclusively through your encrypted Tailscale tunnel. The "insecure" part only refers to HTTP vs HTTPS - and Tailscale already provides encryption.


Phase 4: Login & Verify

The moment of truth. Your bot is running, security is configured, and Tailscale is connecting your devices. Let's access the interface.

1. Check Container Status

Make sure the containers are healthy and staying up:

docker compose ps
Enter fullscreen mode Exit fullscreen mode

Watch it for a few seconds. If the status stays "Up" for more than 10 seconds, you're good.

2. Get Your Tailscale IP

tailscale ip -4
Enter fullscreen mode Exit fullscreen mode

This returns something like 100.x.x.x - your private Tailscale IP address.

3. Access the Web Interface

On your local machine (which must also be connected to Tailscale), open your browser and navigate to:

http://<YOUR_TAILSCALE_IP>:18789
Enter fullscreen mode Exit fullscreen mode

For example: http://100.64.0.1:18789

Enter the Gateway Token you created during setup and click Connect.

Congratulations! You now have a private AI assistant running on your own infrastructure, accessible only through your secure Tailscale network.


Phase 5: Best Practices & Maintenance

Your bot is running, but a few housekeeping practices will keep it healthy and your wallet safe.

Set API Spend Limits

Agentic AI can sometimes get stuck in loops and burn through API credits rapidly. Protect yourself:

  1. Go to your Anthropic Console
  2. Navigate to Settings → Limits
  3. Set a hard monthly budget (e.g., $20)

Do the same for OpenAI if you configured it as a backup.

Enable Sandbox Mode

In the OpenClaw configuration, ensure Sandbox Mode is enabled if available. This restricts the bot's ability to execute unrestricted shell commands on the host system.

Back Up Your Bot's Memory

OpenClaw stores its "long-term memory" in Markdown files. If you lose this directory, the bot forgets everything it knows about you.

Create regular backups:

# Simple backup command
tar -czvf memory_backup_$(date +%F).tar.gz ./openclaw/memory
Enter fullscreen mode Exit fullscreen mode

Consider automating this with a cron job for daily backups.

Monitor Logs

When things go sideways (and they sometimes do), logs are your best friend:

docker compose logs -f
Enter fullscreen mode Exit fullscreen mode

The -f flag follows the log output in real-time. Press Ctrl+C to exit.


Conclusion

You've successfully deployed OpenClaw on a hardened EC2 instance with:

  • Non-standard SSH port (2222) with key-only authentication
  • Dual-layer firewall protection (AWS Security Groups + UFW)
  • Docker containerization for clean isolation
  • Tailscale private networking for secure, zero-trust access
  • No public ports exposed for the application itself

Your AI assistant is now running on infrastructure you control, accessible only to devices on your private Tailnet. No VPN configurations, no exposed ports, no attack surface for the public internet to probe.

Happy building!


Top comments (0)