Introduction

Managed platforms make deployment easy, but they decide where your logs can go. If the destination you need is a custom HTTP endpoint, that decision can leave you stuck.

This article shows how to get past it with Vector, an open-source data pipeline maintained by Datadog. The example is DigitalOcean App Platform forwarding its logs to a custom HTTP endpoint, App Platform sends logs the way it would to Datadog, Vector reshapes them, and your endpoint receives them in the format it expects.

The same idea applies well beyond App Platform. Wherever a managed service exports logs in a fixed format or to a fixed set of destinations, Vector can sit in the middle and reshape them:

  • AWS: CloudWatch Logs can stream through Amazon Data Firehose, which delivers to an HTTP endpoint in its own wrapper format. Vector has a Firehose source that unpacks it.
  • Google Cloud: Cloud Logging sinks can export to Pub/Sub, and Vector can read from a subscription.
  • Azure: Azure Monitor can stream logs to Event Hubs, which exposes a Kafka-compatible endpoint that Vector can read.
  • Heroku, Render, and Vercel: their log drains and log streams send to an endpoint you choose, and Vector can receive them.

Check each provider's current documentation for the exact format. The rest of this article follows the App Platform example.

The limitation: a fixed list of log destinations

App Platform can forward runtime logs only to a fixed list of providers, and a custom HTTP URL is not one of them. According to DigitalOcean's "How to Forward Logs in App Platform" documentation (last verified 13 Jul 2026), the supported destinations are:

  • DigitalOcean Managed OpenSearch
  • OpenSearch
  • Datadog
  • Better Stack (formerly Logtail)

The same page notes that dedicated egress IP addresses cannot be used for log forwarding, so you cannot allowlist the sender by IP.

The usual workarounds each have a cost. Running OpenSearch just to relay logs means operating a stateful service as a pass-through. Shipping logs from the application itself means handling batching and retries yourself and missing anything outside the logger. There is a better option, and it hinges on one detail: the Datadog and OpenSearch destinations both let you supply your own endpoint URL.

What Vector is

Vector is a single long-running process that moves logs, metrics, and traces from one place to another and reshapes them on the way. You describe a pipeline in YAML using three kinds of component:

  • Source: where data comes in, such as a port Vector listens on.
  • Transform: code that reshapes each event, written in VRL, the Vector Remap Language.
  • Sink: where processed data goes out, such as another HTTP endpoint.

Vector can also buffer events to disk, so a short outage downstream does not mean lost logs.

The idea: Let App Platform believe it is talking to Datadog

Configure a Datadog log destination in App Platform, but point its endpoint at a server you control. App Platform POSTs its logs there, with the api_key value in a DD-API-KEY header, and never checks who is on the other end.

That server runs Vector, which accepts the request and translates it into whatever your real endpoint expects. The api_key becomes a shared secret between App Platform and your relay, so App Platform keeps using a supported destination while the translation lives in one small config file you own.

Architecture overview

App Platform (Datadog log destination) | HTTPS POST, api_key in the DD-API-KEY header v +-- Your server -------------------------------------------------------+ | Nginx: TLS and shared-secret check (401 if the secret is wrong) | | | proxy to 127.0.0.1:8282 | | v | | +-- Vector (systemd service) ----------------------------------+ | | | Source: http_server accepts the JSON, no schema check | | | | v | | | | Transform: remap VRL builds a new event | | | | v | | | | Sink: http one event per POST, disk buffer | | | +--------------------------------------------------------------+ | +----------------------------------------------------------------------+ | POST to your endpoint URL v Custom HTTP endpoint (any URL that accepts JSON) 

Nginx authenticates the request, Vector reshapes it, and your endpoint receives an ordinary log POST.

Building the relay, step by step

These steps assume a Linux server with Nginx and a TLS certificate already working for a domain such as logs.example.com. Vector slots in as one extra Nginx route.

1. Generate a secret and install Vector

App Platform cannot be allowlisted by IP, so a shared secret is the only authentication between it and your relay. Generate one, then install Vector:

openssl rand -hex 32 curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev | bash cp ~/.vector/bin/vector /usr/local/bin/vector mkdir -p /etc/vector 

2. Configure Vector

Create /etc/vector/vector.yaml. The transform is where you match your endpoint's schema, so adapt its output fields.

sources: app_platform: type: http_server address: 127.0.0.1:8282 path: /api/v2/logs decoding: codec: json transforms: reshape: type: remap inputs: [app_platform] source: | level = "info" if exists(.status) { level = downcase(to_string!(.status)) } . = { "level": level, "message": .message, "service": .service, "raw": . } sinks: custom_endpoint: type: http inputs: [reshape] uri: https://your-endpoint.example.com/logs method: post request: headers: authorization: "Bearer YOUR_ENDPOINT_TOKEN" content-type: "application/json" encoding: codec: json framing: method: newline_delimited batch: max_events: 1 timeout_secs: 1 buffer: type: disk max_size: 536870912 

Two choices matter here: the plain http_server source rather than datadog_agent, and . = { ... }, which replaces the whole event. The first avoids the extra date field that App Platform sends, which the Datadog-specific source rejects. The second stops the original fields travelling alongside the new ones. The framing and content-type lines make each request a single bare JSON object, which many endpoints expect. Because the file holds a credential, run chmod 600 /etc/vector/vector.yaml.

3. Add the Nginx route

Inside the existing TLS server block, check the secret and proxy to Vector:

location /api/v2/logs { if ($http_dd_api_key != "YOUR_SHARED_SECRET") { return 401; } client_max_body_size 10m; proxy_pass http://127.0.0.1:8282; } 

Reload with nginx -t && systemctl reload nginx.

4. Run Vector under systemd

cat > /etc/systemd/system/vector.service << 'EOF' [Unit] Description=Vector After=network-online.target [Service] ExecStart=/usr/local/bin/vector --config /etc/vector/vector.yaml Restart=on-failure [Install] WantedBy=multi-user.target EOF systemctl daemon-reload && systemctl enable --now vector 

Pointing App Platform at the relay

Add a log_destinations block to the app component in the spec:

log_destinations: - name: custom-endpoint datadog: endpoint: https://logs.example.com/api/v2/logs api_key: YOUR_SHARED_SECRET 

Or set the same values in the console: open the app, go to Settings, click Edit under Log Forwarding, choose Datadog, and fill in the destination name, endpoint, and API key. Make sure the right components are selected, then save. No redeploy is needed, and the same screen is where you rotate the secret later.

To test, deploy any app that writes to stdout, since App Platform forwards whatever the process prints, then watch the relay with journalctl -u vector -f. Events should reach your endpoint within seconds, along with health checks and request logs.

Reusing the relay for other apps

A second app can use the same relay without touching the server: add the same destination in its settings. All its logs then reach the same endpoint, which is fine unless you need to tell apps apart.

To keep them separate, give each app its own Nginx location with its own secret and its own Vector instance. Alternatively, keep one instance and have Nginx tag each request with a header that the transform uses to choose the target.

Conclusion

App Platform's log forwarding is limited to four named providers, but its Datadog destination accepts any endpoint you give it. Putting Vector behind that endpoint turns the limitation into a small translation problem: accept the payload, reshape it with a few lines of VRL, and forward it to the system you actually use. The same pattern fits any managed service that offers a configurable Datadog or HTTP destination.

Sources