Skip to Content

Production Guide: Deploy IT-Tools with Docker Compose + Caddy on Ubuntu

Self-host a private, always-available developer toolbox with 70+ utilities behind automatic HTTPS — no accounts, no SaaS dependencies.

Every developer or sysadmin team eventually builds an informal toolkit of small, one-off utilities: a browser tab that converts epoch timestamps, a bookmark for base64 encoding, a search engine query for generating UUIDs. These scattered dependencies on external SaaS introduce latency, privacy risk, and reliability concerns — the site is down, it requires an account, or a new content-security policy blocks clipboard access. IT-Tools solves this by bundling over 70 such utilities into a single self-hosted web app with no external calls, no sign-up, and sub-millisecond response times on your own hardware.

This guide walks you through a production-quality deployment of IT-Tools on Ubuntu using Docker Compose and Caddy for automatic HTTPS. The result is a private, always-available toolbox accessible to your entire team from a clean subdomain.

Architecture and flow overview

The stack is intentionally minimal. The IT-Tools container serves a static Vue.js SPA on port 80. Caddy acts as the TLS-terminating reverse proxy, automatically obtaining and renewing a Let's Encrypt certificate for your chosen subdomain. There is no database — all tool state is ephemeral and computed in the browser, making the deployment stateless and trivial to scale or back up.

Traffic flow: browser request → Caddy (port 443, TLS) → IT-Tools container (port 80, plain HTTP, Docker bridge network). Docker Compose defines both services on the same user-defined bridge network so Caddy can reach IT-Tools by its service name without exposing any internal ports to the host.

Prerequisites

  • Ubuntu 22.04 or 24.04 server with a public IP address
  • A DNS A record pointing your subdomain (e.g., tools.example.com) to the server IP — propagated before you start
  • Docker Engine 24+ and Docker Compose v2 installed (docker compose plugin, not the legacy binary)
  • Ports 80 and 443 open in your firewall (ufw allow 80/tcp && ufw allow 443/tcp)
  • A non-root sudo user or root shell for initial setup

Step-by-step deployment

1. Create the project directory

mkdir -p /opt/it-tools && cd /opt/it-tools

2. Write the Docker Compose file

services:
  it-tools:
    image: corentinth/it-tools:latest
    container_name: it-tools
    restart: unless-stopped
    networks:
      - web

  caddy:
    image: caddy:2-alpine
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - web
    depends_on:
      - it-tools

networks:
  web:
    driver: bridge

volumes:
  caddy_data:
  caddy_config:

3. Write the Caddyfile

Replace tools.example.com with your actual subdomain.

tools.example.com {
    reverse_proxy it-tools:80
    encode gzip
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        Referrer-Policy no-referrer
    }
}

4. Start the stack

cd /opt/it-tools
docker compose up -d

Watch the Caddy logs for the ACME certificate challenge to complete before testing in the browser:

docker compose logs -f caddy

You should see certificate obtained successfully within 60 seconds for a freshly propagated DNS record.

Configuration and secrets handling

IT-Tools itself has no application secrets or user accounts — it is a stateless, browser-executed tool collection. The only credentials in this stack are the Let's Encrypt ACME email, which Caddy infers from the server environment or can be set explicitly:

tools.example.com {
    tls [email protected]
    reverse_proxy it-tools:80
}

If you need to restrict access to internal users only, add Caddy's built-in IP allowlist or a forward-auth block in front:

tools.example.com {
    @allowed {
        remote_ip 10.0.0.0/8 192.168.0.0/16
    }
    handle @allowed {
        reverse_proxy it-tools:80
    }
    respond 403
}

For teams using a VPN or private network, this one-block change is all you need to ensure the toolbox is never exposed to the open internet while remaining seamlessly available to authenticated team members.

To pin the IT-Tools image version for reproducible builds, replace latest in the Compose file with the specific tag from the Docker Hub release page (e.g., corentinth/it-tools:2024.10.22-3). Use Watchtower or a manual docker compose pull && docker compose up -d in a cron job to manage upgrades on your schedule rather than getting unexpected changes from latest.

Verification

After the stack is up, confirm each layer of the deployment:

# Both containers should show "Up"
docker compose ps

# Caddy should respond on HTTPS with a valid certificate
curl -I https://tools.example.com

# Expected: HTTP/2 200 with x-content-type-options header from Caddy

# Check certificate expiry
echo | openssl s_client -connect tools.example.com:443 2>/dev/null | openssl x509 -noout -dates

Open https://tools.example.com in a browser. You should see the IT-Tools interface with categories like Crypto, Converter, Web, and String. Click the UUID Generator tool and generate a UUID to confirm the JavaScript engine is active. Paste a JSON object into the JSON Formatter to verify clipboard and editor rendering work correctly in your browser.

Common issues and fixes

Caddy shows "certificate authority not accessible" or ACME timeout: Your DNS A record has not fully propagated or port 80 is blocked. Confirm with dig +short tools.example.com that it resolves to your server's IP, and that curl http://tools.example.com/.well-known/acme-challenge/test reaches the server without a 403 or timeout.

Browser shows a blank page after the first load: IT-Tools is a Vue SPA — it lazy-loads chunks on first visit. If your reverse proxy strips the content-type or adds aggressive caching headers that return 304 for stale JavaScript, a hard refresh (Ctrl+Shift+R) or a no-store Cache-Control header in the Caddyfile usually resolves it.

Caddy container keeps restarting: Most often caused by a malformed Caddyfile. Run docker compose logs caddy to see the parse error. Common mistakes include using tabs instead of spaces for indentation or forgetting to close a block with a matching }.

IT-Tools container can't be reached by Caddy even though it is running: Both services must be on the same Docker network. If you started services independently or removed the networks block, run docker compose down && docker compose up -d to recreate the network and reconnect both containers.

Caddy is not renewing the certificate automatically: Certificates auto-renew 30 days before expiry. Confirm Caddy's data volume is persisted (caddy_data:/data is present in the Compose file). If the volume was accidentally removed, Caddy will re-issue a fresh certificate on next restart without any action required.

FAQ

Does IT-Tools send any data to external servers?

No. IT-Tools is a fully client-side Vue.js application. All computation happens in the browser. No input data leaves your server. This makes it suitable for handling sensitive values like JWT tokens, API keys, or private key fingerprints that you would not paste into an external website.

Can I add authentication so only my team can access it?

Yes. The simplest approach is IP-based access control in the Caddyfile (shown in the configuration section above). For user-level auth, you can layer Authentik or Authelia as a forward-auth provider in front of Caddy, or use Caddy's native basicauth directive for simple HTTP basic authentication with a hashed password.

How do I upgrade IT-Tools to a newer version?

Run the following from the project directory:

docker compose pull it-tools
docker compose up -d --no-deps it-tools

The --no-deps flag restarts only the IT-Tools container without touching Caddy, so your TLS termination is uninterrupted during the upgrade.

Is there a way to disable specific tools in IT-Tools?

The open-source edition of IT-Tools does not include a built-in tool disablement feature. All tools are bundled in the image. If you want to limit the surface area, host the image behind an SSO/forward-auth layer that controls who can access the interface, or fork the project and rebuild the image with specific tool directories removed from the Vue router configuration.

Can I run multiple Caddy virtual hosts on the same server?

Yes. Caddy natively supports multiple virtual hosts in a single Caddyfile. Add additional site blocks below the IT-Tools block, each with their own domain and reverse_proxy directive. Caddy will obtain and manage separate TLS certificates for each domain automatically. The shared caddy_data volume stores all certificates together.

What happens if the IT-Tools container crashes?

The restart: unless-stopped policy in the Compose file causes Docker to automatically restart the container whenever it exits unexpectedly. For edge cases where both containers need to come up after a full server reboot, ensure Docker's own service is enabled: systemctl enable docker. Compose services with restart: unless-stopped will then be brought back automatically after the Docker daemon starts.

Does this stack support IPv6?

Caddy supports dual-stack IPv6 natively. To enable it, add an AAAA DNS record for your subdomain and ensure your Docker daemon has IPv6 enabled (/etc/docker/daemon.json with "ipv6": true, "fixed-cidr-v6": "fd00::/80"). No Caddyfile changes are required — Caddy will listen on both IPv4 and IPv6 when the host supports it.

Internal links

Talk to us

If you want this deployed with hardened access controls, monitoring standards, and production runbooks tailored to your environment, our team can help end-to-end.

Contact Us

Production Guide: Deploy Tandoor Recipes with Docker Compose + Caddy + PostgreSQL on Ubuntu
Self-host your recipe manager with automatic TLS, structured meal planning, and persistent PostgreSQL storage