@@ -26,10 +26,13 @@ ENV_FILE="${FULA_CONFIG}/.env"
2626NGINX_CONF=" /etc/nginx/sites-available/fula-gateway"
2727NGINX_ENABLED=" /etc/nginx/sites-enabled/fula-gateway"
2828
29- # Default values
30- DEFAULT_GATEWAY_PORT=" 8080 "
29+ # Default values (must match Dockerfile defaults)
30+ DEFAULT_GATEWAY_PORT=" 9000 "
3131DEFAULT_IPFS_PORT=" 5001"
3232DEFAULT_IPFS_GATEWAY_PORT=" 8081"
33+ DEFAULT_MAX_BODY_SIZE=" 5368709120" # 5GB
34+ DEFAULT_RATE_LIMIT_RPS=" 100"
35+ DEFAULT_REQUEST_TIMEOUT=" 3600" # 1 hour for large uploads
3336
3437# Logging
3538log_info () { echo -e " ${BLUE} [INFO]${NC} $1 " ; }
@@ -244,6 +247,13 @@ collect_configuration() {
244247 # Gateway port
245248 prompt_env " GATEWAY_PORT" " Gateway internal port" " ${GATEWAY_PORT:- $DEFAULT_GATEWAY_PORT } "
246249
250+ # Performance settings
251+ echo " "
252+ log_info " Performance Settings"
253+ prompt_env " MAX_BODY_SIZE" " Max upload size in bytes (default 5GB)" " ${MAX_BODY_SIZE:- $DEFAULT_MAX_BODY_SIZE } "
254+ prompt_env " RATE_LIMIT_RPS" " Rate limit requests per second" " ${RATE_LIMIT_RPS:- $DEFAULT_RATE_LIMIT_RPS } "
255+ prompt_env " REQUEST_TIMEOUT" " Request timeout in seconds" " ${REQUEST_TIMEOUT:- $DEFAULT_REQUEST_TIMEOUT } "
256+
247257 # Confirm
248258 echo " "
249259 echo " ==========================================="
@@ -286,14 +296,20 @@ OAUTH_AUDIENCE=${OAUTH_AUDIENCE:-}
286296CORS_ENABLED=true
287297CORS_ORIGINS=${CORS_ORIGINS}
288298
289- # Gateway Settings
290- GATEWAY_PORT=${GATEWAY_PORT}
291- RUST_LOG=info,fula_cli=debug
299+ # Gateway Settings (FULA_PORT must match Dockerfile)
300+ FULA_HOST=0.0.0.0
301+ FULA_PORT=${GATEWAY_PORT}
302+ RUST_LOG=info,fula_cli=debug,fula_core=debug
303+
304+ # Performance Settings
305+ MAX_BODY_SIZE=${MAX_BODY_SIZE}
306+ RATE_LIMIT_RPS=${RATE_LIMIT_RPS}
307+ REQUEST_TIMEOUT=${REQUEST_TIMEOUT}
292308
293309# IPFS Configuration
294310IPFS_URL=http://localhost:5001
295311
296- # Pinning Service (optional)
312+ # Pinning Service (optional - gateway-level pinning for all uploads )
297313PINNING_SERVICE_ENDPOINT=${PINNING_SERVICE_ENDPOINT:- }
298314PINNING_SERVICE_TOKEN=${PINNING_SERVICE_TOKEN:- }
299315EOF
@@ -312,24 +328,47 @@ create_docker_compose() {
312328 if [[ -n " ${IPFS_DOMAIN} " ]] && [[ " ${IPFS_RUNNING} " != " true" ]]; then
313329 IPFS_SERVICE="
314330 ipfs:
315- image: ipfs/kubo:latest
331+ image: ipfs/kubo:v0.32.1
316332 container_name: fula-ipfs
317333 restart: unless-stopped
318334 volumes:
319335 - ${FULA_HOME} /ipfs:/data/ipfs
320336 ports:
321337 - '127.0.0.1:5001:5001'
322338 - '127.0.0.1:8081:8080'
339+ - '4001:4001' # Swarm TCP
340+ - '4001:4001/udp' # Swarm QUIC
323341 environment:
324342 - IPFS_PROFILE=server
343+ command: ['daemon', '--migrate=true', '--enable-gc']
344+ deploy:
345+ resources:
346+ limits:
347+ memory: 4G
348+ reservations:
349+ memory: 1G
325350 healthcheck:
326351 test: ['CMD-SHELL', 'ipfs id || exit 1']
327352 interval: 30s
328353 timeout: 10s
329354 retries: 3
355+ logging:
356+ driver: json-file
357+ options:
358+ max-size: '100m'
359+ max-file: '3'
330360"
331361 fi
332362
363+ # Determine depends_on based on IPFS configuration
364+ local DEPENDS_ON=" "
365+ if [[ -n " ${IPFS_DOMAIN} " ]] && [[ " ${IPFS_RUNNING} " != " true" ]]; then
366+ DEPENDS_ON="
367+ depends_on:
368+ ipfs:
369+ condition: service_healthy"
370+ fi
371+
333372 cat > " ${FULA_CONFIG} /docker-compose.yml" << EOF
334373version: '3.8'
335374
@@ -340,18 +379,33 @@ services:
340379 restart: unless-stopped
341380 env_file:
342381 - ${ENV_FILE}
382+ environment:
383+ # Override IPFS URL to use Docker network
384+ - IPFS_API_URL=http://ipfs:5001
343385 volumes:
344386 - ${FULA_HOME} /data:/var/lib/fula/data
345387 ports:
346388 - '127.0.0.1:${GATEWAY_PORT} :${GATEWAY_PORT} '
347- depends_on:
348- ${IPFS_DOMAIN: +ipfs: }
349- ${IPFS_DOMAIN: + condition: service_healthy}
389+ deploy:
390+ resources:
391+ limits:
392+ memory: 2G
393+ reservations:
394+ memory: 512M
350395 healthcheck:
351- test: ['CMD', 'curl', '-f', 'http://localhost:${GATEWAY_PORT} /']
396+ # Use HEAD request to health check endpoint (more efficient)
397+ test: ['CMD', 'curl', '-f', '-X', 'HEAD', 'http://localhost:${GATEWAY_PORT} /']
352398 interval: 30s
353399 timeout: 10s
354400 retries: 3
401+ start_period: 30s
402+ logging:
403+ driver: json-file
404+ options:
405+ max-size: '100m'
406+ max-file: '5'
407+ # Graceful shutdown - allow time for in-flight requests
408+ stop_grace_period: 30s${DEPENDS_ON}
355409${IPFS_SERVICE}
356410networks:
357411 default:
@@ -370,9 +424,15 @@ configure_nginx() {
370424 # Gateway nginx config
371425 cat > " ${NGINX_CONF} " << EOF
372426# Fula Gateway - Rate Limiting
373- limit_req_zone \$ binary_remote_addr zone=fula_limit:10m rate=100r /s;
427+ limit_req_zone \$ binary_remote_addr zone=fula_limit:10m rate=${RATE_LIMIT_RPS} r /s;
374428limit_conn_zone \$ binary_remote_addr zone=fula_conn:10m;
375429
430+ # Upstream with keepalive connections
431+ upstream fula_gateway {
432+ server 127.0.0.1:${GATEWAY_PORT} ;
433+ keepalive 32;
434+ }
435+
376436# Gateway Server
377437server {
378438 listen 80;
@@ -384,35 +444,48 @@ server {
384444 add_header X-Content-Type-Options "nosniff" always;
385445 add_header X-XSS-Protection "1; mode=block" always;
386446 add_header Referrer-Policy "strict-origin-when-cross-origin" always;
447+ add_header Content-Security-Policy "default-src 'self'" always;
387448
388449 # Rate limiting
389450 limit_req zone=fula_limit burst=50 nodelay;
390451 limit_conn fula_conn 20;
391452
392- # Request size limit (for large uploads, adjust as needed )
453+ # Request size limit (for large uploads)
393454 client_max_body_size 5G;
394- client_body_timeout 3600s;
395- proxy_read_timeout 3600s;
396- proxy_send_timeout 3600s;
455+ client_body_timeout ${REQUEST_TIMEOUT} s;
456+ proxy_read_timeout ${REQUEST_TIMEOUT} s;
457+ proxy_send_timeout ${REQUEST_TIMEOUT} s;
458+ send_timeout ${REQUEST_TIMEOUT} s;
459+
460+ # Increase buffer sizes for S3 clients that send many headers
461+ proxy_buffer_size 16k;
462+ proxy_buffers 4 32k;
463+ proxy_busy_buffers_size 64k;
464+ large_client_header_buffers 4 32k;
397465
398466 location / {
399- proxy_pass http://127.0.0.1: ${GATEWAY_PORT} ;
467+ proxy_pass http://fula_gateway ;
400468 proxy_http_version 1.1;
401469 proxy_set_header Host \$ host;
402470 proxy_set_header X-Real-IP \$ remote_addr;
403471 proxy_set_header X-Forwarded-For \$ proxy_add_x_forwarded_for;
404472 proxy_set_header X-Forwarded-Proto \$ scheme;
405473 proxy_set_header Connection "";
406474
407- # Buffering settings for large files
475+ # Disable buffering for streaming uploads/downloads
408476 proxy_buffering off;
409477 proxy_request_buffering off;
478+
479+ # Pass through all S3 headers
480+ proxy_pass_request_headers on;
410481 }
411482
412- # Health check endpoint (no rate limit)
413- location = /health {
483+ # Health check endpoint (no rate limit, efficient HEAD request )
484+ location = /_health {
414485 limit_req off;
415- proxy_pass http://127.0.0.1:${GATEWAY_PORT} /;
486+ limit_conn off;
487+ proxy_pass http://fula_gateway/;
488+ proxy_method HEAD;
416489 }
417490}
418491EOF
@@ -502,7 +575,8 @@ configure_firewall() {
502575
503576 # Allow IPFS swarm if running local IPFS
504577 if [[ -n " ${IPFS_DOMAIN} " ]] && [[ " ${IPFS_RUNNING} " != " true" ]]; then
505- ufw allow 4001/tcp # IPFS swarm
578+ ufw allow 4001/tcp # IPFS swarm TCP
579+ ufw allow 4001/udp # IPFS swarm QUIC
506580 fi
507581
508582 ufw --force enable
569643 log_success " Systemd service created"
570644}
571645
646+ # Configure IPFS settings for optimal performance
647+ configure_ipfs_settings () {
648+ if [[ -z " ${IPFS_DOMAIN} " ]] && [[ " ${IPFS_RUNNING} " != " true" ]]; then
649+ return 0
650+ fi
651+
652+ log_info " Configuring IPFS settings..."
653+
654+ # Wait for IPFS to be ready
655+ local retries=30
656+ while ! curl -s http://localhost:5001/api/v0/id > /dev/null 2>&1 ; do
657+ retries=$(( retries - 1 ))
658+ if [[ $retries -eq 0 ]]; then
659+ log_warn " IPFS not responding, skipping configuration"
660+ return 0
661+ fi
662+ sleep 2
663+ done
664+
665+ # Configure IPFS for production
666+ # Increase connection limits
667+ curl -s -X POST " http://localhost:5001/api/v0/config?arg=Swarm.ConnMgr.LowWater&arg=100&json=true" > /dev/null
668+ curl -s -X POST " http://localhost:5001/api/v0/config?arg=Swarm.ConnMgr.HighWater&arg=400&json=true" > /dev/null
669+ curl -s -X POST " http://localhost:5001/api/v0/config?arg=Swarm.ConnMgr.GracePeriod&arg=60s&json=true" > /dev/null
670+
671+ # Enable QUIC transport
672+ curl -s -X POST " http://localhost:5001/api/v0/config?arg=Swarm.Transports.Network.QUIC&arg=true&json=true" > /dev/null
673+
674+ # Increase API timeout for large operations
675+ curl -s -X POST " http://localhost:5001/api/v0/config?arg=API.HTTPHeaders.Access-Control-Allow-Origin&arg=[\" *\" ]&json=true" > /dev/null
676+
677+ log_success " IPFS configured for production"
678+ }
679+
572680# Start services
573681start_services () {
574682 log_info " Starting services..."
@@ -579,6 +687,9 @@ start_services() {
579687 # Wait for services to start
580688 sleep 5
581689
690+ # Configure IPFS if running
691+ configure_ipfs_settings
692+
582693 log_success " Services started"
583694}
584695
@@ -603,12 +714,22 @@ verify_installation() {
603714 log_warn " Gateway container not yet running (may be pulling image)"
604715 fi
605716
606- # Check gateway health (via localhost)
717+ # Check gateway health (via localhost) using HEAD request
607718 sleep 10
608- if curl -s http://localhost:${GATEWAY_PORT} / > /dev/null 2>&1 ; then
719+ if curl -s -X HEAD -o /dev/null -w " %{http_code} " http://localhost:${GATEWAY_PORT} / | grep -q " 200 " ; then
609720 log_success " Gateway responding on localhost:${GATEWAY_PORT} "
610721 else
611722 log_warn " Gateway not responding yet (may still be starting)"
723+ log_info " Check logs: docker compose -f ${FULA_CONFIG} /docker-compose.yml logs gateway"
724+ fi
725+
726+ # Check IPFS if configured
727+ if [[ -n " ${IPFS_DOMAIN} " ]] || [[ " ${IPFS_RUNNING} " == " true" ]]; then
728+ if curl -s http://localhost:5001/api/v0/id > /dev/null 2>&1 ; then
729+ log_success " IPFS daemon responding on localhost:5001"
730+ else
731+ log_warn " IPFS daemon not responding"
732+ fi
612733 fi
613734
614735 # Check SSL
@@ -637,7 +758,12 @@ verify_installation() {
637758 echo " Stop: systemctl stop fula-gateway"
638759 echo " Restart: systemctl restart fula-gateway"
639760 echo " Status: systemctl status fula-gateway"
640- echo " Logs: journalctl -u fula-gateway -f"
761+ echo " Logs: docker compose -f ${FULA_CONFIG} /docker-compose.yml logs -f"
762+ echo " "
763+ echo " Configuration files:"
764+ echo " Environment: ${ENV_FILE} "
765+ echo " Docker: ${FULA_CONFIG} /docker-compose.yml"
766+ echo " Nginx: ${NGINX_CONF} "
641767 echo " "
642768
643769 if [[ ! " ${IPFS_RUNNING} " == " true" ]] && [[ -z " ${IPFS_DOMAIN} " ]]; then
@@ -648,6 +774,13 @@ verify_installation() {
648774 log_warn " 2. Re-run this script with an IPFS domain"
649775 fi
650776
777+ echo " "
778+ echo " Troubleshooting:"
779+ echo " View gateway logs: docker compose -f ${FULA_CONFIG} /docker-compose.yml logs gateway"
780+ echo " View IPFS logs: docker compose -f ${FULA_CONFIG} /docker-compose.yml logs ipfs"
781+ echo " Test health: curl -I https://${FULA_DOMAIN} /"
782+ echo " Rebuild image: cd /path/to/fula-api && docker build -t ghcr.io/functionland/fula-gateway:latest ."
783+ echo " "
651784 echo " ==========================================="
652785
653786 if [[ $errors -gt 0 ]]; then
0 commit comments