diff --git a/defaults/main.yml b/defaults/main.yml
index 006ce89a4cfa6e86aed99b7ccbdb9d7f7bc7106c..108e4578f6e658b2ea59d4c96e38e1232b0dd2ed 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -40,7 +40,7 @@ funkwhale_letsencrypt_certbot_flags:
 funkwhale_letsencrypt_enabled: true
 funkwhale_letsencrypt_skip_cert: false
 
-funkwhale_nginx_csp_policy: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; object-src 'none'; media-src 'self' data:"
+funkwhale_nginx_csp_policy: "default-src 'self'; connect-src https: wss: http: ws: 'self' 'unsafe-eval'; script-src 'self' 'wasm-unsafe-eval'; style-src https: http: 'self' 'unsafe-inline'; img-src https: http: 'self' data:; font-src https: http: 'self' data:; media-src https: http: 'self' data:; object-src 'none'"
 funkwhale_redis_managed: true
 funkwhale_api_ip: 127.0.0.1
 funkwhale_api_port: 5000
diff --git a/templates/funkwhale_proxy.conf.j2 b/templates/funkwhale_proxy.conf.j2
index fadc957a7e3028397b68e57f2e0e11ce05fa9f6b..2651ab8133244f73edf4fb016f43e144209358bc 100644
--- a/templates/funkwhale_proxy.conf.j2
+++ b/templates/funkwhale_proxy.conf.j2
@@ -1,15 +1,16 @@
 # global proxy conf
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
+
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-proxy_set_header X-Forwarded-Proto $scheme;
+proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
 {% if not funkwhale_nginx_tls_termination -%}
-proxy_set_header X-Forwarded-Host $host:$server_port;
-proxy_set_header X-Forwarded-Port $server_port;
+proxy_set_header X-Forwarded-Host $http_x_forwarded_host;
+proxy_set_header X-Forwarded-Port $http_x_forwarded_port;
 proxy_redirect off;
 {% endif -%}
 
 # websocket support
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
-proxy_set_header Connection "upgrade";
+proxy_set_header Connection $funkwhale_connection_upgrade;
diff --git a/templates/nginx.conf.j2 b/templates/nginx.conf.j2
index 6712e059c9be72749fdd11dce6599a2ff8614657..612039bb7171938ea867cb2c8490831622df493a 100644
--- a/templates/nginx.conf.j2
+++ b/templates/nginx.conf.j2
@@ -1,16 +1,38 @@
 # {{ ansible_managed }}
+# This template was based on Funkwhale's nginx.template at ae2402618846d414cb1b4e7237c4ce43d8c8837c
+
+upstream funkwhale-api {
+    server {{ funkwhale_api_ip }}:{{ funkwhale_api_port }};
+}
+
 {% if funkwhale_nginx_tls_termination -%}
 server {
     listen 80;
     listen [::]:80;
     server_name {{ funkwhale_hostname }};
-    location / { return 301 https://$host$request_uri; }
+
+    location /.well-known/ {
+        allow all;
+        include /etc/nginx/funkwhale_proxy.conf;
+        proxy_pass   http://{{ funkwhale_api_ip }}:{{ funkwhale_api_port }}/.well-known/;
+    }
+
+    location / {
+        return 301 https://$host$request_uri;
+    }
 }
 {% endif -%}
 
+# Required for websocket support.
+map $http_upgrade $funkwhale_connection_upgrade {
+    default upgrade;
+    ''      close;
+}
+
 server {
     listen {% if funkwhale_nginx_tls_termination %}443 ssl http2{% else %}80{% endif %};
     listen [::]:{% if funkwhale_nginx_tls_termination %}443 ssl http2{% else -%}80{% endif %};
+    charset     utf-8;
     server_name {{ funkwhale_hostname }};
     {% if funkwhale_nginx_tls_termination -%}
     {% if funkwhale_ssl_key_path -%}
@@ -19,25 +41,37 @@ server {
     {% else -%}
     ssl_certificate /etc/letsencrypt/live/{{ funkwhale_hostname }}/fullchain.pem;
     ssl_certificate_key /etc/letsencrypt/live/{{ funkwhale_hostname }}/privkey.pem;
-    {% endif -%}
+    {% endif -%} {# funkwhale_ssl_key_path #}
+
     {% if funkwhale_nginx_tls_configure_ciphers -%}
-    # from https://cipherli.st/
-    ssl_prefer_server_ciphers on;
-    ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
-    ssl_ecdh_curve secp384r1;
-    ssl_session_timeout  10m;
+    # Many of these are overridden by matching settings outside of any server{} block!
+    # https://github.com/mozilla/ssl-config-generator/issues/76
+    ssl_ecdh_curve X25519:prime256v1:secp384r1;
+    # https://ssl-config.mozilla.org/#server=nginx&config=modern
+    ssl_session_timeout 1d;
     ssl_session_cache shared:SSL:10m;
     ssl_session_tickets off;
+    ssl_protocols TLSv1.3;
+    ssl_prefer_server_ciphers off;
     ssl_stapling on;
     ssl_stapling_verify on;
-    {% endif -%}
-    add_header Strict-Transport-Security "max-age=63072000; preload";
-    {% endif -%}
+    {% if ansible_os_family in ["Debian", "Archlinux"] -%}
+    ssl_trusted_certificates /etc/ssl/certs/ca-certificates.crt;
+    {% elif ansible_os_family in ["RedHat"] -%}
+    ssl_trusted_certificates /etc/ssl/certs/ca-bundle.crt;
+    {% else -%} {# Missing: Suse, Gentoo, Mandrake #}
+    # Please set ssl_trusted_certificates using funkwhale_nginx_additional_config and open an issue
+    {% endif -%} {# ansible_os_family #}
+    {% endif -%} {# funkwhale_nginx_tls_configure_ciphers #}
+    add_header Strict-Transport-Security "max-age=31536000" always;
+    {% endif -%} {# funkwhale_nginx_tls_termination #}
 
     {% if funkwhale_nginx_csp_policy -%}
-    # Security-related headers
     add_header Content-Security-Policy "{{ funkwhale_nginx_csp_policy }}";
     {% endif -%}
+    add_header Referrer-Policy "strict-origin-when-cross-origin";
+    add_header X-Frame-Options "SAMEORIGIN" always;
+    add_header Service-Worker-Allowed "/";
 
     root {{ funkwhale_frontend_path }};
 
@@ -72,79 +106,101 @@ server {
     {% endif -%}
     # end of compression settings
 
-    location / {
+    location /api/ {
         include /etc/nginx/funkwhale_proxy.conf;
-        # this is needed if you have file import via upload enabled
+        # This is needed if you have file import via upload enabled.
         client_max_body_size {{ funkwhale_nginx_max_body_size }};
-        proxy_pass   http://{{ funkwhale_api_ip }}:{{ funkwhale_api_port }}/;
+        proxy_pass   http://funkwhale-api;
+    }
+    {% if funkwhale_disable_django_admin -%}
+    location /api/admin/ {
+        # disable access to API admin dashboard
+        return 403;
     }
+    {% endif -%}
 
-    location /front/ {
+    location / {
         alias {{ funkwhale_frontend_path }}/;
-        expires 30d;
+        expires 1d;
         add_header Pragma public;
         add_header Cache-Control "public, must-revalidate, proxy-revalidate";
         add_header Service-Worker-Allowed "/";
+        try_files $uri $uri/ /index.html;
+    }
+
+    location ~ "/(front/)?embed.html" {
+        add_header Content-Security-Policy "connect-src https: http: 'self'; default-src 'self'; script-src 'self' unpkg.com 'unsafe-inline' 'unsafe-eval'; style-src https: http: 'self' 'unsafe-inline'; img-src https: http: 'self' data:; font-src https: http: 'self' data:; object-src 'none'; media-src https: http: 'self' data:";
+        add_header Referrer-Policy "strict-origin-when-cross-origin";
+
+        alias {{ funkwhale_frontend_path }}/embed.html;
+        expires 1d;
     }
 
     location /federation/ {
         include /etc/nginx/funkwhale_proxy.conf;
-        proxy_pass   http://{{ funkwhale_api_ip }}:{{ funkwhale_api_port }}/federation/;
+        proxy_pass   http://funkwhale-api;
     }
 
-    # You can comment this if you do not plan to use the Subsonic API
+    # You can comment this if you do not plan to use the Subsonic API.
     location /rest/ {
         include /etc/nginx/funkwhale_proxy.conf;
-        proxy_pass   http://{{ funkwhale_api_ip }}:{{ funkwhale_api_port }}/api/subsonic/rest/;
+        proxy_pass   http://funkwhale-api/api/subsonic/rest/;
     }
 
     location /.well-known/ {
+        allow all;
         include /etc/nginx/funkwhale_proxy.conf;
-        proxy_pass   http://{{ funkwhale_api_ip }}:{{ funkwhale_api_port }}/.well-known/;
+        proxy_pass   http://funkwhale-api;
     }
 
-    location /media/ {
-        alias {{ funkwhale_media_path }}/;
+    # Allow direct access to only specific subdirectories in /media
+    location /media/__sized__/ {
+        alias {{ funkwhale_media_path }}/__sized__/;
+        add_header Access-Control-Allow-Origin '*';
+    }
+
+    # Allow direct access to only specific subdirectories in /media
+    location /media/attachments/ {
+        alias {{ funkwhale_media_path }}/attachments/;
+        add_header Access-Control-Allow-Origin '*';
+    }
+
+    # Allow direct access to only specific subdirectories in /media
+    location /media/dynamic_preferences/ {
+        alias {{ funkwhale_media_path }}/dynamic_preferences/;
+        add_header Access-Control-Allow-Origin '*';
     }
 
     {% if funkwhale_external_storage_enabled -%}
-    # Comment the previous location and uncomment this one if you're storing
-    # media files in a S3 bucket
+    # This is an internal location that is used to serve
+    # media (uploaded) files once correct permission / authentication
+    # has been checked on API side.
     location ~ /_protected/media/(.+) {
-        # Needed to ensure DSub auth isn't forwarded to S3/Minio, see #932
-        proxy_set_header Authorization "";
         internal;
-        proxy_pass $1;
+        # Needed to ensure DSub auth isn't forwarded to S3/Minio, see #932.
+        proxy_set_header Authorization "";                                  # S3
+        proxy_pass $1;                                                      # S3
+        add_header Access-Control-Allow-Origin '*';
     }
     {% else -%}
-    location /_protected/media {
-        # this is an internal location that is used to serve
-        # audio files once correct permission / authentication
-        # has been checked on API side
+    location /_protected/media/ {
         internal;
-        alias   {{ funkwhale_media_path }};
+        alias   {{ funkwhale_media_path }}/;
+        add_header Access-Control-Allow-Origin '*';
     }
     {% endif %}
 
-    location /_protected/music {
-        # this is an internal location that is used to serve
-        # audio files once correct permission / authentication
-        # has been checked on API side
-        # Set this to the same value as your MUSIC_DIRECTORY_PATH setting
+    location /_protected/music/ {
+        # This is an internal location that is used to serve
+        # local music files once correct permission / authentication
+        # has been checked on API side.
         internal;
-        alias   {{ funkwhale_music_path }};
+        alias   {{ funkwhale_music_path }}/;
+        add_header Access-Control-Allow-Origin '*';
     }
 
-    location /staticfiles/ {
-        # django static files
-        alias {{ funkwhale_static_path }}/;
+    location /manifest.json {
+        return 302 /api/v1/instance/spa-manifest.json;
     }
-{% if funkwhale_disable_django_admin -%}
-
-    location /api/admin/ {
-        # disable access to API admin dashboard
-        return 403;
-    }
-{% endif -%}
 {{ funkwhale_nginx_additional_config }}
 }