Skip to main content

Overview

CORS (Cross-Origin Resource Sharing) configuration is essential for enabling Web Audio API features like the audio visualizer. Without proper CORS headers, browsers will block access to audio stream data for security reasons.
Current Issue: Without CORS headers, you may see:
MediaElementAudioSource outputs zeroes due to CORS access restrictions
The audio will still play, but visual effects won’t be reactive to the music.

System URLs

La Urban uses the following URL structure:
  • Frontend: laurban.cl
  • Stream URL: https://stream.laurban.cl:8000/media
  • API: azura.laurban.cl

Server Configuration

1

Choose your server type

Select the appropriate configuration based on your streaming server setup.
2

Apply CORS headers

Configure the headers according to your server type below.
3

Verify configuration

Test that CORS headers are being sent correctly.
If your stream is behind Nginx, add these headers to your server configuration:
server {
    listen 8000 ssl;
    server_name stream.laurban.cl;

    location /media {
        # CORS headers for Web Audio API
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Range, Content-Type' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length, Content-Range' always;
        
        # Handle OPTIONS preflight requests
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            add_header 'Content-Length' 0;
            return 204;
        }
        
        # Your existing proxy configuration (Icecast, Shoutcast, etc.)
        proxy_pass http://localhost:8000/media;
        # ... rest of configuration
    }
}

Option 2: Apache

For Apache servers, add to .htaccess or VirtualHost configuration:
<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Methods "GET, OPTIONS"
    Header set Access-Control-Allow-Headers "Range, Content-Type"
    Header set Access-Control-Expose-Headers "Content-Length, Content-Range"
</IfModule>

Option 3: Icecast

For Icecast streaming servers, edit /etc/icecast2/icecast.xml:
<http-headers>
    <header name="Access-Control-Allow-Origin" value="*" />
    <header name="Access-Control-Allow-Methods" value="GET, OPTIONS" />
    <header name="Access-Control-Allow-Headers" value="Range, Content-Type" />
</http-headers>

Option 4: Cloudflare

If using Cloudflare as a proxy:
1

Navigate to Transform Rules

Go to RulesTransform RulesHTTP Response Headers
2

Create a new rule

Create a rule for your stream domain:
  • Set static: Access-Control-Allow-Origin*
  • Set static: Access-Control-Allow-MethodsGET, OPTIONS

Traefik Configuration

Basic CORS Middleware

Add these labels to your Traefik configuration:
# CORS Headers - Traefik v3 syntax
traefik.http.middlewares.azuracast-cors.headers.customresponseheaders.Access-Control-Allow-Origin=*
traefik.http.middlewares.azuracast-cors.headers.customresponseheaders.Access-Control-Allow-Methods=GET,HEAD,OPTIONS
traefik.http.middlewares.azuracast-cors.headers.customresponseheaders.Access-Control-Allow-Headers=*
traefik.http.middlewares.azuracast-cors.headers.customresponseheaders.Access-Control-Max-Age=3600

# Standard headers (maintain these)
traefik.http.middlewares.azuracast-cors.headers.accesscontrolallowheaders=*
traefik.http.middlewares.azuracast-cors.headers.accesscontrolallowmethods=GET,HEAD,OPTIONS
traefik.http.middlewares.azuracast-cors.headers.accesscontrolmaxage=100
traefik.http.middlewares.azuracast-cors.headers.addvaryheader=true

Mobile-Optimized CORS

For maximum mobile compatibility (especially iOS Safari):
# CORS optimized for mobile devices
traefik.http.middlewares.azuracast-cors.headers.accesscontrolalloworigin=https://laurban.cl
traefik.http.middlewares.azuracast-cors.headers.accesscontrolallowmethods=GET,POST,OPTIONS,HEAD
traefik.http.middlewares.azuracast-cors.headers.accesscontrolallowheaders=Origin,Content-Type,Accept,Authorization,Cache-Control,X-Requested-With,Range
traefik.http.middlewares.azuracast-cors.headers.accesscontrolexposeheaders=Content-Length,Content-Range,Accept-Ranges,Icy-Br,Icy-Description,Icy-Genre,Icy-MetaInt,Icy-Name,Icy-Pub,Icy-Url
traefik.http.middlewares.azuracast-cors.headers.accesscontrolallowcredentials=false
traefik.http.middlewares.azuracast-cors.headers.accesscontrolmaxage=3600
traefik.http.middlewares.azuracast-cors.headers.addvaryheader=true

Docker Compose Example

services:
  azuracast:
    labels:
      # ... your existing labels ...
      
      # Add these CORS headers:
      - "traefik.http.middlewares.azuracast-cors.headers.accesscontrolalloworigin=*"
      - "traefik.http.middlewares.azuracast-cors.headers.accesscontrolallowcredentials=false"
      - "traefik.http.middlewares.azuracast-cors.headers.accesscontrolexposeheaders=Content-Length,Content-Range,Icy-Br,Icy-Description,Icy-Genre,Icy-MetaInt,Icy-Name,Icy-Pub,Icy-Url"

Verification

Command Line Test

After applying changes, verify CORS headers are present:
curl -I https://stream.laurban.cl:8000/media
You should see:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS

Browser Console Test

Test from your browser’s developer console:
fetch('https://stream.laurban.cl:8000/media', { method: 'HEAD' })
  .then(r => console.log(r.headers.get('Access-Control-Allow-Origin')))

Mobile Verification

Test with mobile user agent:
curl -H "Origin: https://laurban.cl" \
     -H "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X)" \
     -I https://stream.laurban.cl:8000/media
Expected output:
access-control-allow-origin: *
access-control-allow-methods: GET,POST,OPTIONS,HEAD
access-control-expose-headers: Content-Length,Content-Range...

Testing After Configuration

1

Restart your server

Restart the streaming server or reverse proxy to apply changes.
2

Clear browser cache

Clear your browser cache or test in incognito/private mode.
3

Test on mobile

For mobile testing, clear cache and test in private browsing mode.
4

Verify visualization

The logo should react to audio with pulsing, rotation, and glow effects.

Important Notes

Cross-Origin Attribute: The HTML <audio> element must include crossorigin="anonymous" to request CORS headers from the server.
iOS Safari: iOS Safari is the most strict browser with CORS policies. The Access-Control-Allow-Origin header is mandatory for iOS compatibility.

Current Implementation Status

  • HTML: crossorigin="anonymous" added to <audio> element
  • JavaScript: Visualizer gracefully degrades if CORS is blocked
  • Fallback: Uses CSS animation when Web Audio API is unavailable
  • Server: CORS headers need to be configured on streaming server

Without CORS Headers

What works:
  • Audio playback continues normally
  • Basic player controls function
  • Metadata updates work
What doesn’t work:
  • Audio-reactive logo visualization
  • Frequency-based visual effects
  • Real-time audio analysis
Fallback behavior:
  • Simple CSS pulse animation
  • Static visual effects
  • No frequency detection

With CORS Configured

Once CORS is properly configured, the logo will react to audio with:
  • 🎵 Pulse with bass/kick detection
  • 🎸 Rotation with mid frequencies
  • ✨ Brightness with highs
  • 💫 Dynamic shadow effects
  • 🎨 Color saturation changes

Build docs developers (and LLMs) love