user root; worker_processes auto; pid /run/nginx.pid; include /etc/nginx/modules-enabled/*.conf; events { worker_connections 768; # multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; reset_timedout_connection on; client_body_timeout 20s; client_header_timeout 20s; proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; send_timeout 300s; include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 3; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css text/javascript application/javascript application/json application/transit+json image/svg+xml; map $http_upgrade $connection_upgrade { default upgrade; '' close; } proxy_cache_path /tmp/cache/ levels=2:2 keys_zone=penpot:20m; proxy_cache_methods GET HEAD; proxy_cache_valid any 48h; proxy_cache_key "$host$request_uri"; server { listen 3449 default_server; server_name _; client_max_body_size 300M; charset utf-8; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffer_size 16k; proxy_busy_buffers_size 24k; # essentially, proxy_buffer_size + 2 small buffers of 4k proxy_buffers 32 4k; resolver 127.0.0.11 ipv6=off; etag off; root /home/penpot/penpot/frontend/resources/public; location @handle_redirect { set $redirect_uri "$upstream_http_location"; set $redirect_host "$upstream_http_x_host"; set $redirect_cache_control "$upstream_http_cache_control"; set $real_mtype "$upstream_http_x_mtype"; proxy_set_header Host "$redirect_host"; proxy_hide_header etag; proxy_hide_header x-amz-id-2; proxy_hide_header x-amz-request-id; proxy_hide_header x-amz-meta-server-side-encryption; proxy_hide_header x-amz-server-side-encryption; proxy_pass $redirect_uri; add_header x-internal-redirect "$redirect_uri"; add_header x-cache-control "$redirect_cache_control"; add_header cache-control "$redirect_cache_control"; add_header content-type "$real_mtype"; } location /assets { proxy_pass http://127.0.0.1:6060/assets; recursive_error_pages on; proxy_intercept_errors on; error_page 301 302 307 = @handle_redirect; } location /internal/assets { internal; alias /home/penpot/penpot/backend/assets; add_header x-internal-redirect "$upstream_http_x_accel_redirect"; } # On production, this is controlled by ELB location /api/export { proxy_pass http://127.0.0.1:6061; } location /api { proxy_pass http://127.0.0.1:6060/api; proxy_buffering off; proxy_http_version 1.1; } location /admin { proxy_pass http://127.0.0.1:6063/admin; } location /webhooks { proxy_pass http://127.0.0.1:6060/webhooks; } location /dbg { proxy_pass http://127.0.0.1:6060/dbg; } location /telemetry { proxy_pass http://127.0.0.1:6070/inbox; } location /playground { alias /home/penpot/penpot/experiments/; add_header Cache-Control "no-cache, max-age=0"; autoindex on; } location /ws/notifications { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_pass http://127.0.0.1:6060/ws/notifications; } location /storybook { alias /home/penpot/penpot/frontend/storybook-static/; autoindex on; } location / { location ~ ^/github/penpot-files/(?[a-zA-Z0-9\-\_\.]+) { proxy_pass https://raw.githubusercontent.com/penpot/penpot-files/main/$template_file; proxy_hide_header Access-Control-Allow-Origin; proxy_set_header User-Agent "curl/7.74.0"; proxy_set_header Host "raw.githubusercontent.com"; proxy_set_header Accept "*/*"; add_header Access-Control-Allow-Origin $http_origin; proxy_buffering off; } location ~ ^/internal/gfonts/font/(?.+) { proxy_pass https://fonts.gstatic.com/s/$font_file; proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Cross-Origin-Resource-Policy; proxy_hide_header Link; proxy_hide_header Alt-Svc; proxy_hide_header Cache-Control; proxy_hide_header Expires; proxy_hide_header Cross-Origin-Opener-Policy; proxy_hide_header Report-To; proxy_ignore_headers Set-Cookie Vary Cache-Control Expires; proxy_set_header User-Agent "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"; proxy_set_header Host "fonts.gstatic.com"; proxy_set_header Accept "*/*"; proxy_cache penpot; add_header Access-Control-Allow-Origin $http_origin; add_header Cache-Control max-age=86400; add_header X-Cache-Status $upstream_cache_status; } location ~ ^/internal/gfonts/css { proxy_pass https://fonts.googleapis.com/css?$args; proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Cross-Origin-Resource-Policy; proxy_hide_header Link; proxy_hide_header Alt-Svc; proxy_hide_header Cache-Control; proxy_hide_header Expires; proxy_ignore_headers Set-Cookie Vary Cache-Control Expires; proxy_set_header User-Agent "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"; proxy_set_header Host "fonts.googleapis.com"; proxy_set_header Accept "*/*"; proxy_cache penpot; add_header Access-Control-Allow-Origin $http_origin; add_header Cache-Control max-age=86400; add_header X-Cache-Status $upstream_cache_status; } location ~ ^/js/config.js$ { add_header Cache-Control "no-store, no-cache, max-age=0" always; } location ~* \.(js|css|jpg|svg|png|mjs|map)$ { # We set no cache only on devenv add_header Cache-Control "no-store, no-cache, max-age=0" always; # add_header Cache-Control "max-age=604800" always; # 7 days } location ~ ^/(/|css|fonts|images|js|wasm|mjs|map) { } location ~ ^/[^/]+/(.*)$ { return 301 " /404"; } add_header Last-Modified $date_gmt; add_header Cache-Control "no-store, no-cache, max-age=0" always; if_modified_since off; try_files $uri /index.html$is_args$args /index.html =404; } } }