Vector 0.60.0 on AWS User Guide
Overview
This guide covers launching and using the Vector 0.60.0 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg log management listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Vector is an observability data pipeline from Datadog's open source team. It collects logs and metrics from sources (HTTP, files, syslog, Kafka, agents and many more), transforms them with the Vector Remap Language (VRL) and routes them to sinks such as Amazon S3, CloudWatch Logs, Kinesis, OpenSearch, Loki or another Vector. It is a single Rust binary configured with one YAML file.
The cloudimg image ships Vector as a ready, authenticated HTTPS log ingest endpoint:
- HTTPS from the first boot. nginx is the only network entry point and accepts events on
https://<your-host>/ingestwith a certificate generated on your instance's first boot. Port 80 only redirects to HTTPS. - A credential unique to your instance. Every ingest request needs HTTP Basic Auth as the user
ingest. The password is generated on first boot and written to the root only file/root/vector-credentials.txt; nginx stores only its bcrypt hash and the credential never reaches Vector. No password is baked into the image and no two instances share one. - Vector on loopback only. Vector's HTTP source (port 9880) and its GraphQL API (port 8686, used by
vector topandvector tap) are bound to127.0.0.1. Never open them in a security group. - Fail closed. nginx refuses to start until first boot has written the certificate and the credential, so the endpoint is never served without a login.
- Sandboxed service. Vector runs as the unprivileged
vectoruser with no Linux capabilities, a read only system and write access only to/var/lib/vector. - Instance role access for Vector only. Vector uses the instance's IAM role via IMDSv2; no other service on the image can reach IMDS (the base OS's cloud-init and SSM Agent aside). Attach an IAM role to use its S3, CloudWatch Logs and Kinesis sinks.
- Fixed host name and real client addresses. Requests for a host name the instance does not serve are dropped, nginx passes the real client address (client supplied
X-Forwarded-Forheaders are overwritten), and cross site browser requests are refused. - Key only SSH. Password logins, root logins and X11 forwarding are switched off.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Vector 0.60.0 (the unmodified upstream release package vector_0.60.0-1_amd64.deb, checksum and signature verified, MPL-2.0), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The starter pipeline is: HTTPS ingest, a VRL transform that stamps each event with received_by and received_at, and a file sink under /var/lib/vector/ingest/. Replace the file sink with your own destinations (Step 7).
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 22 (SSH) from your own networks and TCP 443 (the ingest endpoint) from the networks your log agents are in. TCP 80 only redirects to HTTPS and is optional. If your agents run inside the same VPC, allow 443 from the VPC CIDR only.
- Optional: an IAM instance profile if Vector should write to Amazon S3, CloudWatch Logs or Kinesis (Step 7).
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Vector 0.60.0 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair, a security group as above and, if you will use the AWS sinks, an IAM instance profile. Under Advanced details, keep Metadata version at V2 only and set Metadata response hop limit to 1.
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--iam-instance-profile Name=<your-instance-profile> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled,HttpPutResponseHopLimit=1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=vector}]'
The AMI is IMDSv2 only. A hop limit of 1 keeps the instance role's credentials on the instance itself (containers or forwarded traffic cannot reach the metadata service).
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Vector 0.60.0 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot generates the certificate and the credential, then nginx starts in front of Vector:
systemctl is-active vector nginx vector-firstboot
sudo test -f /var/lib/cloudimg/vector-firstboot.done && echo FIRSTBOOT_DONE
vector --version
curl -s http://127.0.0.1:8686/health; echo
active
active
active
FIRSTBOOT_DONE
vector 0.60.0 (x86_64-unknown-linux-gnu 0d0b358 2026-10-19 16:56:14.309955068)
{"ok":true}
Only SSH and nginx listen on public addresses; Vector listens on loopback:
sudo ss -Hlntp | awk '{print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort
0.0.0.0:22 users:(("sshd"),("systemd"))
0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
127.0.0.1:8686 users:(("vector"))
127.0.0.1:9880 users:(("vector"))
[::]:22 users:(("sshd"),("systemd"))
[::]:443 users:(("nginx"),("nginx"),("nginx"))
[::]:80 users:(("nginx"),("nginx"),("nginx"))
Step 4: Get your ingest URL and credential
The URL, the user name and the certificate path are in the root only credentials file:
sudo grep -E '^VECTOR_(INGEST_URL|INGEST_USER|CA_CERT|SINK_DIR)=' /root/vector-credentials.txt
VECTOR_INGEST_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/ingest
VECTOR_INGEST_USER=ingest
VECTOR_CA_CERT=/etc/ssl/vector/vector.crt
VECTOR_SINK_DIR=/var/lib/vector/ingest
The password is the VECTOR_INGEST_PASSWORD line of the same file: sudo grep '^VECTOR_INGEST_PASSWORD=' /root/vector-credentials.txt. Store it in your password manager or secrets store; it is unique to this instance.
The URL uses the instance's public DNS name from EC2 instance metadata (IMDSv2), or its public or private IPv4 address when it has no public name. The certificate names that host plus the instance's public and private IP addresses, so agents can use any of them:
openssl x509 -in /etc/ssl/vector/vector.crt -noout -subject -ext subjectAltName -enddate
subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = cloudimg
X509v3 Subject Alternative Name:
DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost
notAfter=<date about 27 months after first boot>
Step 5: Check the login
Without the credential a request is refused, a wrong password is refused, only POST /ingest is accepted, and port 80 redirects to HTTPS. The commands below read the password from the credentials file into a shell variable and pass it to curl through a file descriptor, so it never appears in the process list or your shell history:
U=$(sudo sed -n 's/^VECTOR_INGEST_URL=//p' /root/vector-credentials.txt); H=${U#https://}; H=${H%%/*}
PW=$(sudo sed -n 's/^VECTOR_INGEST_PASSWORD=//p' /root/vector-credentials.txt)
CA=/etc/ssl/vector/vector.crt
curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/ingest"
curl -s -o /dev/null -w 'no login -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -X POST -d '{}' "$U"
curl -s -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "ingest:not-the-password"\n') -X POST -d '{}' "$U"
curl -s -o /dev/null -w 'ingest + password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "ingest:%s"\n' "$PW") -X POST -d '{"message":"login check"}' "$U"
curl -s -o /dev/null -w 'GET /ingest -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "ingest:%s"\n' "$PW") "$U"
http:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/ingest
no login -> HTTP 401
wrong password -> HTTP 401
ingest + password -> HTTP 200
GET /ingest -> HTTP 403
--resolve sends the request to this instance while keeping the real host name, so the certificate check passes. From another machine, drop --resolve and use the URL directly.
Step 6: Send events and see them arrive
The endpoint takes newline delimited JSON, one event per line. Send three events, then read the newest lines of today's file sink:
U=$(sudo sed -n 's/^VECTOR_INGEST_URL=//p' /root/vector-credentials.txt); H=${U#https://}; H=${H%%/*}
PW=$(sudo sed -n 's/^VECTOR_INGEST_PASSWORD=//p' /root/vector-credentials.txt)
CA=/etc/ssl/vector/vector.crt
for svc in web-01 web-02 db-01; do
printf '{"message":"order placed","service":"checkout","host":"%s","level":"info"}\n' "$svc"
done | curl -s -o /dev/null -w 'ingest -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" \
-K <(printf 'user = "ingest:%s"\n' "$PW") -H 'Content-Type: application/x-ndjson' --data-binary @- "$U"
sleep 2
sudo tail -n 3 /var/lib/vector/ingest/ingest-$(date -u +%F).log | jq -c '{host, level, message, received_by}'
ingest -> HTTP 200
{"host":"web-01","level":"info","message":"order placed","received_by":"vector"}
{"host":"web-02","level":"info","message":"order placed","received_by":"vector"}
{"host":"db-01","level":"info","message":"order placed","received_by":"vector"}
Each event also carries received_at, the time Vector accepted it, added by the stamp transform. To watch events flow live, run vector top (throughput per component) or vector tap --outputs-of stamp (the events themselves) on the instance; both use the loopback GraphQL API.
Step 7: Route events to your own destinations
The pipeline lives in /etc/vector/vector.yaml. Add a sink, point its inputs at stamp, then check and apply the change:
sudo nano /etc/vector/vector.yaml
sudo vector validate /etc/vector/vector.yaml
sudo systemctl reload vector
Amazon S3, using the instance's IAM role (attach a role that allows s3:PutObject on the bucket):
sinks:
archive_s3:
type: aws_s3
inputs: [stamp]
bucket: <your-bucket>
region: <region>
key_prefix: "vector/%Y/%m/%d/"
compression: gzip
encoding:
codec: json
CloudWatch Logs (the role needs logs:CreateLogStream, logs:PutLogEvents and logs:DescribeLogStreams):
sinks:
cloudwatch:
type: aws_cloudwatch_logs
inputs: [stamp]
region: <region>
group_name: <your-log-group>
stream_name: "{{ host }}"
encoding:
codec: json
Vector uses the instance's IAM role via IMDSv2; no other service on the image can reach IMDS. You never put AWS access keys in the configuration. Other destinations (OpenSearch, Loki, Kafka, HTTP, another Vector) work the same way; see the upstream sink reference. Keep any destination password or token in a root only file referenced from the configuration, never in a world readable file. To stop writing the local copy, remove the ingest_archive sink.
Step 8: Send logs from your servers
Any agent that can POST JSON over HTTPS works. Give it the URL, the user ingest, the password, and the instance's certificate so it can verify the connection. Copy the certificate to each agent host first (it is public, not a secret):
scp -i <your-key.pem> ubuntu@<vector-host>:/etc/ssl/vector/vector.crt ./vector.crt
Fluent Bit ([OUTPUT] section):
[OUTPUT]
Name http
Match *
Host <vector-host>
Port 443
URI /ingest
Format json_lines
tls On
tls.verify On
tls.ca_file /etc/fluent-bit/vector.crt
http_User ingest
http_Passwd <VECTOR_INGEST_PASSWORD>
Another Vector (an edge agent forwarding to this instance):
sinks:
to_central:
type: http
inputs: [your_source]
uri: "<VECTOR_INGEST_URL>"
method: post
encoding:
codec: json
framing:
method: newline_delimited
auth:
strategy: basic
user: ingest
password: "${VECTOR_INGEST_PASSWORD}"
tls:
ca_file: /etc/vector/central.crt
Keep the password in the agent's own secret store or a root only file rather than in a world readable configuration. Agents send no browser Origin header, so the image's cross site request guard does not affect them.
To accept other protocols (syslog, Fluent forward, Kafka), add the source in vector.yaml bound to the address you need and open that port in the security group only to your VPC or VPN CIDRs, never to 0.0.0.0/0. Those ports stay closed until you open them.
Step 9: Use your own DNS name or certificate
The served host name is fixed by configuration, never taken from a request. To serve the endpoint under your own DNS name, point the name at the instance and run the helper, which records the name, regenerates the self signed certificate for it, updates the credentials file and reloads nginx:
sudo vector-set-hostname <your-dns-name>
Run the same command after a stop and start if the instance's public DNS name changed (an Elastic IP avoids that), because a request for a name the instance does not serve is dropped.
To use a certificate from your own CA or a public CA instead, replace /etc/ssl/vector/vector.crt (full chain) and /etc/ssl/vector/vector.key (mode 0600, owner root), then run sudo nginx -t && sudo systemctl reload nginx. Alternatively, put the instance behind an Application Load Balancer with an AWS Certificate Manager certificate that forwards to port 443.
Step 10: Security notes
Vector runs as its own unprivileged user with no capabilities and a read only system, and nginx cannot reach the instance metadata service:
systemctl show vector -p User -p NoNewPrivileges -p ProtectSystem -p ProtectHome -p CapabilityBoundingSet
systemctl show nginx -p IPAddressDeny
CapabilityBoundingSet=
User=vector
ProtectHome=yes
ProtectSystem=strict
NoNewPrivileges=yes
IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32
SSH accepts keys only: passwords, root logins and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-cloudimg.conf, which sorts before every other SSH setting. Check the effective values:
sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|x11forwarding|pubkeyauthentication) '
permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
x11forwarding no
A request carrying a foreign browser Origin is refused, even with the right password, so a web page cannot post events through a browser that holds the credential:
U=$(sudo sed -n 's/^VECTOR_INGEST_URL=//p' /root/vector-credentials.txt); H=${U#https://}; H=${H%%/*}
PW=$(sudo sed -n 's/^VECTOR_INGEST_PASSWORD=//p' /root/vector-credentials.txt)
curl -s -o /dev/null -w 'Origin evil.example ingest -> HTTP %{http_code}\n' --cacert /etc/ssl/vector/vector.crt --resolve "$H:443:127.0.0.1" -K <(printf 'user = "ingest:%s"\n' "$PW") -H 'Origin: https://evil.example' -d '{"message":"x"}' "$U"
Origin evil.example ingest -> HTTP 403
Other points:
- Only root can change the pipeline; Vector fetches no URL a remote party supplies.
- nginx passes the real client address of every request;
X-Forwarded-Forheaders sent by clients are ignored. - The AMI requires IMDSv2. Restrict port 443 to the networks your agents use, and never open 8686 or 9880.
- To rotate the password, generate a new one, write its bcrypt hash with
sudo htpasswd -iB /etc/nginx/vector.htpasswd ingest(it reads the new password from standard input), update/root/vector-credentials.txt, reload nginx and update your agents.
Support and licensing
Vector is open source under the Mozilla Public License 2.0; the image ships the unmodified upstream release package and there is no per host or per CPU licence fee. The AMI price covers cloudimg's hardening, first boot setup and support.
- Email: support@cloudimg.co.uk
- Website: https://www.cloudimg.co.uk
For sources, transforms, sinks and VRL, see the upstream Vector documentation.
Vector is named only to identify the unmodified upstream software, which is developed by Datadog, Inc. cloudimg is not affiliated with or endorsed by Datadog.