Self-Hosting with No SSL Certificate

The following is a guide for setting up Hudu with no SSL certificate. We only recommend this option if the server is going to be used without outside internet access, and will be accessible only on an internal network.
If you are looking to use a free SSL certificate that auto-renews for you, or a custom SSL certificate, you may want to read this article for alternative options: Getting Started with Hudu Self-Hosted.

Prerequisites

In order to self-host Hudu, you will need:
  • Server with at least 4GB memory and at least 1 CPU (as long as there is no contention), with Ubuntu  (22.04 LTS, or newer) as the OS.
  • SMTP server for sending outgoing mail.

Instructions

  • SSH into the server you are wishing to host Hudu on.
  • Install Docker CE on the server. Setup instructions can be found here.
    • Do not use SNAP to install Docker - this will cause issues later on.
  • Create a blank directory named hudu2 on the home directory. On Ubuntu, you can do this by typing:

    mkdir ~/hudu2
  • Move into the directory. On Ubuntu:

    cd ~/hudu2
  • Place a file named docker-compose.yml in the directory.
  • Expand to copy content for docker-compose.yml file
    volumes:  
      postgres_data: {}
      app_data: {}
      redis_data: {}
    services:
      db:    
        image: 'postgres:17.2'    
        volumes:      
          - postgres_data:/var/lib/postgresql/data
        env_file:
          - '.env'
        logging:
          driver: "json-file"
          options:
              max-file: "5"
              max-size: "10m"
        restart: unless-stopped
      redis:
        image: 'redis:latest'
        command: redis-server
        volumes:
          - redis_data:/var/lib/redis/data
        restart: unless-stopped
      app:    
        image: hududocker/hudu:latest
        env_file:
          - '.env'
        volumes:
          - app_data:/var/www/hudu2/public/uploads/
          - app_data:/var/www/hudu2/uploads/      
          - app_data:/var/lib/app/data
        depends_on:      
          - db
          - redis
        logging:
          driver: "json-file"
          options:
              max-file: "5"
              max-size: "100m"
        restart: unless-stopped
      worker:
        depends_on:
          - db
          - redis
        image: hududocker/hudu:latest
        command: bundle exec sidekiq -C config/sidekiq.yml
        volumes:
          - app_data:/var/www/hudu2/public/uploads/
          - app_data:/var/www/hudu2/uploads/
          - '.:/app'
        env_file:
          - '.env'
        logging:
          driver: "json-file"
          options:
              max-file: "5"
              max-size: "100m"
        restart: unless-stopped
      nginx:
        image: lscr.io/linuxserver/nginx
        container_name: nginx
        cap_add:
          - NET_ADMIN
        env_file: 
          - '.env'
        depends_on:
          - app
        volumes:
          - /var/www/hudu2/config:/config
        ports: 
          - 80:80
          - 443:443
        restart: unless-stopped

     

        Already have a production environment and want to update your docker-compose.yml file? Please visit our Upgrade Postgres in a Production Environment article for more information!

     

  • Generate your .env file by running this command:

    cd ~/hudu2 && bash <(curl -fsSL https://raw.githubusercontent.com/Hudu-Technologies-Inc/self-hosting/refs/heads/main/hudu-env-wizard.sh)
    • Follow the prompts to provide your subdomain and root domain.
    • Choose your preferred storage method (y for S3, n for local storage). If you select S3, you will be prompted to enter your S3 configuration details. These settings can always be edited later.
    • Warning: Never edit the generated encryption keys in this file. These keys are used to decrypt passwords and two-factor authentication data. Changing them will result in permanent data loss or errors when creating, viewing, or editing passwords and when using two-factor authentication.
  • Edit your .env file, add the following line, and save the file:

    DISABLE_SSL=true

    It is critical that you store an exact copy of the .env file in a secure location. Your encryption and secure keys are located in this file, and you can lose access to passwords and more if this file is lost.

Note: If you are using DISABLE_SSL=true with an upstream TLS proxy, you should also set BEHIND_TLS_PROXY=true to ensure proper HTTPS URL behavior.

  • When both files are residing within the directory, run the command to start your Hudu instance:

    sudo docker compose up -d
  • Now, run to stop your Hudu instance:

    sudo docker compose down
  • Navigate to /var/www/hudu2/config/nginx/:
cd /var/www/hudu2/config/nginx/
  • Create a file named proxy.conf and add the content below:

    Expand to copy content for proxy.conf 
    ## Version 5/13/2026 - Changelog: proxy.conf file /var/www/hudu2/config/nginx/proxy.conf
    
    client_body_buffer_size 128k;
    
    # Timeout if the real server is dead
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    
    # Advanced Proxy Config
    send_timeout 5m;
    proxy_read_timeout 240;
    proxy_send_timeout 240;
    proxy_connect_timeout 240;
    
    # TLS 1.3 early data
    # proxy_set_header Early-Data $ssl_early_data;
    
    # Basic Proxy Config
    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 https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Ssl off;
    proxy_redirect http:// $scheme://;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    # proxy_cookie_path / "/; HTTPOnly; Secure"; # enable at your own risk, may break certain apps
    proxy_cache_bypass $cookie_session;
    proxy_no_cache $cookie_session;
    proxy_buffers 32 4k;
    proxy_headers_hash_bucket_size 128;
    proxy_headers_hash_max_size 1024;
    
  • Navigate to /var/www/hudu2/config/nginx/site-confs/:

    cd /var/www/hudu2/config/nginx/site-confs/
  • Edit the file named default.conf and replace ALL of the contents with this file named default:
  • Expand to copy the content for the default.conf file
    ## Version 5/14/2026 - Changelog: Default file for no-ssl
    
    # redirect all traffic to https
    server {
      listen 80 default_server;
      listen [::]:80 default_server;
      server_name _;
    
      root   /var/www/hudu2/public;
      index  index.html;
      
       location = /.well-known/oauth-authorization-server {
    	limit_except GET { deny all; }
    	client_max_body_size 1k;
    	#add_header Content-Type application/json;
    	proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_set_header Host $host;
    	proxy_set_header X-Forwarded-Proto https;
    	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    	proxy_pass http://app:3000;
        }
    
        location = /.well-known/oauth-protected-resource {
    	limit_except GET { deny all; }
    	client_max_body_size 1k;
    	#add_header Content-Type application/json;
    	proxy_http_version 1.1;
            proxy_set_header Connection "";
    	proxy_set_header Host $host;
    	proxy_set_header X-Forwarded-Proto https;
    	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://app:3000;
        }
    
        location /mcp {     
            proxy_read_timeout 3600s;     
            proxy_send_timeout 3600s;     
            proxy_buffering off;              
            proxy_cache off;     
            proxy_set_header Connection '';     
            proxy_http_version 1.1;
    	chunked_transfer_encoding off;
    	gzip off;
    	proxy_set_header Host $host;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://app:3000;
        }
    
      location ~ /\. {
        deny all;
     }
      location ~* ^.+\.(rb|log)$ {
        deny all;
      }
      location /cable {        
          proxy_pass http://app:3000/cable;       
    	  proxy_http_version 1.1;      
    	  proxy_set_header Upgrade $http_upgrade;        
    	  proxy_set_header Connection "upgrade";        
    	  proxy_set_header Host $host;        
    	  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         
    	  proxy_read_timeout 240s;    
    	  proxy_send_timeout 240s;         
    	  proxy_set_header X-Forwarded-Proto $scheme;        
    	  proxy_set_header X-Real-IP $remote_addr;        
    	  proxy_pass_request_headers on;        
    	  proxy_buffering off;        
    	  proxy_redirect off;        
    	  break;    
      }
      # send non-static file requests to the app server
      location / {
        try_files $uri @rails;
      }
    
      location @rails {
        include /config/nginx/proxy.conf;
        proxy_pass http://app:3000;
      }
    
    }
    
    # enable subdomain method reverse proxy confs
    include /config/nginx/proxy-confs/*.subdomain.conf;
    # enable proxy cache for auth
    proxy_cache_path cache/ keys_zone=auth_cache:10m;
  • Navigate back to the hudu2 folder. On Ubuntu:

    cd ~/hudu2
  • Start the instance again:

    sudo docker compose up -d
  • Your Hudu should now be up and running! Visit your domain to confirm. If you see a Hudu sign-up screen, it's successful. Head over to the Hudu HQ Billing Portal for a license key.
  • If you don't see this screen, contact support, and please provide logs:

    sudo docker compose logs

 

Additional Environment Options

When should I use DISABLE_SSL?

Answer: Use DISABLE_SSL=true when TLS/SSL is handled outside of Hudu, such as by Cloudflare, nginx, AWS ALB, or another reverse proxy. This disables Hudu's HTTP to HTTPS redirect on port 81.

When should I set BEHIND_TLS_PROXY?

Answer: Use BEHIND_TLS_PROXY=true together with DISABLE_SSL=true when Hudu is behind a reverse proxy that handles TLS/SSL, such as Cloudflare, nginx, AWS ALB, or another proxy.

When should I use USE_ALTERNATE_IP_CHECK?

Answer: Use USE_ALTERNATE_IP_CHECK=true if Hudu is behind a proxy and client IP addresses are not being detected correctly. This tells Hudu to use request.ip instead of request.remote_ip.

How do I increase the upload size limit?

Answer: Use MAX_FILE_SIZE to set the upload limit in MB. For example, MAX_FILE_SIZE=250 sets the limit to 250 MB. The default is 100 MB.

How do I use S3-compatible storage?

Answer: Use the S3 variables when USE_LOCAL_FILESYSTEM is not set to true. Configure S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET, S3_REGION, and, if needed, S3_ENDPOINT for providers like Wasabi or MinIO.

When should I use S3_FORCE_PATH_STYLE?

Answer: Use S3_FORCE_PATH_STYLE=true for MinIO or other S3-compatible providers that require path-style bucket access instead of virtual-hosted-style access.

When should I use S3_REMOVE_ENCRYPTION_HEADER?

Answer: Use S3_REMOVE_ENCRYPTION_HEADER=true if your S3-compatible provider rejects AWS server-side encryption headers.

When should I use S3_TURN_OFF_VERIFY_PEER?

Answer: Use S3_TURN_OFF_VERIFY_PEER=true only for trusted S3 endpoints where TLS certificate verification must be skipped. This is not recommended for public or untrusted endpoints.

Can I change rate limiting?

Answer: Use RATE_LIMIT_REQUESTS to adjust the per-IP request limit and LOGIN_THROTTLE_PERIOD_SECONDS to adjust the login throttle window.

Can I disable rate limiting?

Answer: You can use DISABLE_RACK_ATTACK=true to disable rate limiting, but this is not recommended unless rate limiting is handled upstream by a trusted proxy, firewall, or WAF.

How do I allow iframes or embedded content?

Answer: Use WHITELISTED_FRAME_SRC to allow specific iframe sources. Use DISABLE_FRAME_CSP=true only if you need to allow all iframes, as this weakens Content Security Policy protections.

How do I allow external media sources?

Answer: Use WHITELIST_MEDIA_SRC with a comma-separated list of approved media sources.

Was this article helpful?
1 out of 1 found this helpful