<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerAdmin admin@learnitive.com
    ServerName edu.learnitive.com
    DocumentRoot /var/www/edu.learnitive.com/public_html/dist

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/edu.learnitive.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/edu.learnitive.com/privkey.pem

    ProxyPreserveHost On
    ProxyRequests Off
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"

    ProxyPass        /api/ http://127.0.0.1:4210/api/
    ProxyPassReverse /api/ http://127.0.0.1:4210/api/
    ProxyPass        /sitemap.xml http://127.0.0.1:4210/sitemap.xml
    ProxyPassReverse /sitemap.xml http://127.0.0.1:4210/sitemap.xml
    ProxyPass        /robots.txt http://127.0.0.1:4210/robots.txt
    ProxyPassReverse /robots.txt http://127.0.0.1:4210/robots.txt
    ProxyPass        /blog/rss.xml http://127.0.0.1:4210/blog/rss.xml
    ProxyPassReverse /blog/rss.xml http://127.0.0.1:4210/blog/rss.xml

    ProxyPass        /collab-live ws://127.0.0.1:4211/collab-live
    ProxyPassReverse /collab-live ws://127.0.0.1:4211/collab-live
    ProxyPass        /collab-signal ws://127.0.0.1:4211/collab-signal
    ProxyPassReverse /collab-signal ws://127.0.0.1:4211/collab-signal

    # Public Cloud Terminal WebSocket endpoint. ProxyPass strips the public
    # /console-gateway/ prefix so the private gateway receives /console/<id>.
    # Use a direct WebSocket proxy instead of relying on per-vhost rewrite
    # matching; this also makes the route deterministic when Apache evaluates
    # directory rewrites for non-file requests.
    ProxyPass        /console-gateway/ ws://127.0.0.1:9887/ retry=0
    ProxyPassReverse /console-gateway/ ws://127.0.0.1:9887/

    # Never expose implementation paths. The renderer itself accepts only
    # loopback requests from this vhost.
    <LocationMatch "^/(?:__learnitive|__texise|server|deploy|packages|interactive-services|learnitive-services)(?:/|$)">
        Require all denied
    </LocationMatch>

    <Directory "/var/www/edu.learnitive.com/public_html/dist">
        Options -Indexes
        AllowOverride None
        Require all granted
        DirectoryIndex disabled
        RewriteEngine On
        RewriteCond %{REQUEST_URI} !^/(?:api|collab-live|collab-signal|console-gateway)/ [NC]
        RewriteCond %{REQUEST_METHOD} ^(?:GET|HEAD)$ [NC]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ http://127.0.0.1:4210/__learnitive/render/$1 [P,L,QSA]
    </Directory>

    AddType application/wasm .wasm
    AddType image/x-icon .ico
    AddType image/svg+xml .svg
    AddType application/manifest+json .webmanifest
    AddType font/woff2 .woff2
    AddType font/otf .otf
    AddType font/ttf .ttf
    <Files "manifest.json">
        ForceType application/manifest+json
    </Files>

    Header always set Cross-Origin-Opener-Policy "same-origin"
    Header always set Cross-Origin-Embedder-Policy "credentialless"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"
    # Staging must never become an indexed public surface, even if robots.txt is cached or misconfigured.
    Header always set X-Robots-Tag "noindex, nofollow, noarchive"
    Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://www.youtube.com https://s.ytimg.com https://fast.wistia.com https://*.wistia.net https://src.litix.io https://*.sentry-cdn.com https://webr.r-wasm.org https://www.statcounter.com https://www.googletagmanager.com https://challenges.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data: https://*.wistia.com; connect-src 'self' https: https://challenges.cloudflare.com wss://edu.learnitive.com http://127.0.0.1:* http://localhost:*; frame-src 'self' https://preview.learnitive.com https://www.youtube.com https://www.youtube-nocookie.com https://fast.wistia.net https://fast.wistia.com https://challenges.cloudflare.com; worker-src 'self' blob: https://webr.r-wasm.org; child-src 'self' blob:; manifest-src 'self'; media-src 'self' blob: data: https://*.wistia.com https://*.wistia.net https://*.wistia.land https://*.akamaized.net https://embedwistia-a.akamaihd.net"
    Header always set Strict-Transport-Security "max-age=31536000"

    <FilesMatch "^(index\.html|site\.webmanifest|manifest\.webmanifest|manifest\.json|learnitive-texlive-sw\.js|release\.json)$">
        Header always set Cache-Control "no-cache, no-store, must-revalidate"
    </FilesMatch>
    <FilesMatch "^(favicon\.ico|favicon\.svg|favicon-96x96\.png|apple-touch-icon\.png)$">
        Header always set Cache-Control "public, max-age=86400"
    </FilesMatch>
    <LocationMatch "^/(assets|compiler|learnitive-icons|learnitive-fonts|locales|texlive|mathlive-fonts)/">
        Header always set Cache-Control "public, max-age=31536000, immutable"
    </LocationMatch>
    <LocationMatch "^/learnitive-media/(?:blog|docs)/[A-Za-z0-9-]+\.(?:png|jpg|webp)$">
        Header always set Cache-Control "public, max-age=31536000, immutable"
    </LocationMatch>
    <Location "/compiler/status.json">
        Header always set Cache-Control "no-cache, no-store, must-revalidate"
    </Location>
    <LocationMatch "^/texlive/(bundle\.json|cache-manifest-(text|binary)\.txt)$">
        Header always set Cache-Control "no-cache, no-store, must-revalidate"
    </LocationMatch>

    ErrorLog ${APACHE_LOG_DIR}/learnitive-edu-error.log
    CustomLog ${APACHE_LOG_DIR}/learnitive-edu-access.log combined
</VirtualHost>
</IfModule>
