diff --git a/.env b/.env new file mode 100644 index 0000000..103a4e4 --- /dev/null +++ b/.env @@ -0,0 +1,31 @@ +# Traefik Variables +TRAEFIK_IMAGE_TAG=traefik:2.9 +TRAEFIK_LOG_LEVEL=WARN +TRAEFIK_ACME_EMAIL=callvaldemar@gmail.com +TRAEFIK_HOSTNAME=traefik.ollama.heyvaldemar.net +# Basic Authentication for Traefik Dashboard +# Username: traefikadmin +# Passwords must be encoded using MD5, SHA1, or BCrypt https://hostingcanada.org/htpasswd-generator/ +TRAEFIK_BASIC_AUTH=traefikadmin:$$2y$$10$$sMzJfirKC75x/hVpiINeZOiSm.Jkity9cn4KwNkRvO7hSQVFc5FLO + +# Ollama Variables +# For configurations using AMD GPUs, use ollama/ollama:rocm +OLLAMA_IMAGE_TAG=ollama/ollama:0.3.12 +OLLAMA_HOSTNAME=ollama.heyvaldemar.net +# Define the models to be installed in the Ollama service. Separate each model name with a comma +# Recommended sources for finding models compatible with Ollama: +# 1. Ollama Official Website - https://ollama.com/library: Visit the official Ollama website for detailed information +# on available models and how to use them with the platform +# 2. Hugging Face Model Hub - https://huggingface.co/models: Ollama supports many models from Hugging Face +# You can search and explore models across various categories such as NLP, vision, and more +# 3. Open WebUI - https://openwebui.com: While primarily designed for Open WebUI, it hosts a range of models +# that might also be adaptable for use with Ollama. Ensure compatibility before use +OLLAMA_INSTALL_MODELS=llama3,codegemma,mistral +# Number of GPUs to allocate to the Ollama service. +# Specify '1' to use a single GPU, ideal for environments where resources are shared or for less GPU-intensive tasks +# Use 'all' to allocate all available GPUs, which is suitable for high-performance tasks that benefit from parallel computing across multiple GPUs +# Make sure to uncomment and configure the corresponding GPU section in the YAML file for NVIDIA GPU support if you wish to use your GPU for processing +OLLAMA_GPU_COUNT=all + +# Open WebUI Variables +WEBUI_IMAGE_TAG=ghcr.io/open-webui/open-webui:0.3 diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..89b098c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +github: heyvaldemar +patreon: heyvaldemar +ko_fi: heyvaldemar +custom: ['paypal.com/paypalme/heyValdemarCOM', 'buymeacoffee.com/heyValdemar', 'ko-fi.com/heyValdemar'] diff --git a/.github/workflows/00-deployment-verification.yml b/.github/workflows/00-deployment-verification.yml new file mode 100644 index 0000000..8171b03 --- /dev/null +++ b/.github/workflows/00-deployment-verification.yml @@ -0,0 +1,50 @@ +name: Deployment Verification + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + deploy-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Create necessary Docker networks + run: | + docker network create ollama-network || true + docker network create traefik-network || true + + - name: Start up services using Docker Compose + run: docker compose -f ollama-traefik-letsencrypt-docker-compose.yml up -d + + - name: Modify /etc/hosts for internal routing + run: | + echo "127.0.0.1 ollama.heyvaldemar.net" | sudo tee -a /etc/hosts + echo "127.0.0.1 traefik.ollama.heyvaldemar.net" | sudo tee -a /etc/hosts + + - name: Print Docker Compose services status + run: docker ps + + - name: Wait for the application to be ready via Traefik + run: | + echo "Checking the routing and availability of application via Traefik..." + timeout 5m bash -c 'while ! curl -fsSLk "https://ollama.heyvaldemar.net"; do echo "Waiting for the application to be ready..."; sleep 10; done' + + - name: Inspect Network Configuration + run: | + docker network inspect ollama-network + docker network inspect traefik-network + + - name: Shutdown Docker Compose services + if: always() + run: docker compose -f ollama-traefik-letsencrypt-docker-compose.yml down diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c63c60 --- /dev/null +++ b/.gitignore @@ -0,0 +1,284 @@ +# Created by https://www.toptal.com/developers/gitignore/api/git,macos,xcode,jekyll,packer,ansible,vagrant,windows,notepadpp,terraform,powershell,terragrunt,sublimetext,ansibletower,visualstudiocode,linux +# Edit at https://www.toptal.com/developers/gitignore?templates=git,macos,xcode,jekyll,packer,ansible,vagrant,windows,notepadpp,terraform,powershell,terragrunt,sublimetext,ansibletower,visualstudiocode,linux + +### Ansible ### +*.retry + +### AnsibleTower ### +# Ansible runtime and backups +*.original +*.tmp +*.bkp +*.*~ + +# Tower runtime roles +roles/** +!roles/requirements.yml + +# Avoid plain-text passwords +*pwd* +*pass* +*password* +*.txt + +# Exclude all binaries +*.bin +*.jar +*.tar +*.zip +*.gzip +*.tgz + + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Jekyll ### +_site/ +.sass-cache/ +.jekyll-cache/ +.jekyll-metadata +# Ignore folders generated by Bundler +.bundle/ +vendor/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### NotepadPP ### +# Notepad++ backups # +*.bak + +### Packer ### +# Cache objects +packer_cache/ + +# Crash log +crash.log + +# https://www.packer.io/guides/hcl/variables +# Exclude all .pkrvars.hcl files, which are likely to contain sensitive data, +# such as password, private keys, and other secrets. These should not be part of +# version control as they are data points which are potentially sensitive and +# subject to change depending on the environment. +# +*.pkrvars.hcl + +# For built boxes +*.box + +### Packer Patch ### +# ignore temporary output files +output-*/ + +### PowerShell ### +# Exclude packaged modules + +# Exclude .NET assemblies from source +*.dll + +### SublimeText ### +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json +sftp-config-alt*.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### Terraform ### +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +### Terragrunt ### +# terragrunt cache directories +**/.terragrunt-cache/* + +# Terragrunt debug output file (when using `--terragrunt-debug` option) +# See: https://terragrunt.gruntwork.io/docs/reference/cli-options/#terragrunt-debug +terragrunt-debug.tfvars.json + +### Vagrant ### +# General +.vagrant/ + +# Log files (if you are creating logs in debug mode, uncomment this) +# *.log + +### Vagrant Patch ### + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Xcode ### +## User settings +xcuserdata/ + +## Xcode 8 and earlier +*.xcscmblueprint +*.xccheckout + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno +**/xcshareddata/WorkspaceSettings.xcsettings + +# End of https://www.toptal.com/developers/gitignore/api/git,macos,xcode,jekyll,packer,ansible,vagrant,windows,notepadpp,terraform,powershell,terragrunt,sublimetext,ansibletower,visualstudiocode,linux \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..53227c9 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# Ollama with Let's Encrypt Using Docker Compose + +[![Deployment Verification](https://github.com/heyvaldemar/ollama-traefik-letsencrypt-docker-compose/actions/workflows/00-deployment-verification.yml/badge.svg)](https://github.com/heyvaldemar/ollama-traefik-letsencrypt-docker-compose/actions) + +The badge displayed on my repository indicates the status of the deployment verification workflow as executed on the latest commit to the main branch. + +**Passing**: This means the most recent commit has successfully passed all deployment checks, confirming that the Docker Compose setup functions correctly as designed. + +๐Ÿ“™ The complete installation guide is available on my [website](https://www.heyvaldemar.com/install-ollama-using-docker-compose/). + +โ— Change variables in the `.env` to meet your requirements. + +๐Ÿ’ก Note that the `.env` file should be in the same directory as `ollama-traefik-letsencrypt-docker-compose.yml`. + +Create networks for your services before deploying the configuration using the commands: + +`docker network create traefik-network` + +`docker network create ollama-network` + +Deploy Ollama using Docker Compose: + +`docker compose -f ollama-traefik-letsencrypt-docker-compose.yml -p ollama up -d` + +# Author + +Iโ€™m Vladimir Mikhalev, the [Docker Captain](https://www.docker.com/captains/vladimir-mikhalev/), but my friends can call me Valdemar. + +๐ŸŒ My [website](https://www.heyvaldemar.com/) with detailed IT guides\ +๐ŸŽฌ Follow me on [YouTube](https://www.youtube.com/channel/UCf85kQ0u1sYTTTyKVpxrlyQ?sub_confirmation=1)\ +๐Ÿฆ Follow me on [Twitter](https://twitter.com/heyValdemar)\ +๐ŸŽจ Follow me on [Instagram](https://www.instagram.com/heyvaldemar/)\ +๐Ÿงต Follow me on [Threads](https://www.threads.net/@heyvaldemar)\ +๐Ÿ˜ Follow me on [Mastodon](https://mastodon.social/@heyvaldemar)\ +๐ŸงŠ Follow me on [Bluesky](https://bsky.app/profile/heyvaldemar.bsky.social)\ +๐ŸŽธ Follow me on [Facebook](https://www.facebook.com/heyValdemarFB/)\ +๐ŸŽฅ Follow me on [TikTok](https://www.tiktok.com/@heyvaldemar)\ +๐Ÿ’ป Follow me on [LinkedIn](https://www.linkedin.com/in/heyvaldemar/)\ +๐Ÿˆ Follow me on [GitHub](https://github.com/heyvaldemar) + +# Communication + +๐Ÿ‘พ Chat with IT pros on [Discord](https://discord.gg/AJQGCCBcqf)\ +๐Ÿ“ง Reach me at ask@sre.gg + +# Give Thanks + +๐Ÿ’Ž Support on [GitHub](https://github.com/sponsors/heyValdemar)\ +๐Ÿ† Support on [Patreon](https://www.patreon.com/heyValdemar)\ +๐Ÿฅค Support on [BuyMeaCoffee](https://www.buymeacoffee.com/heyValdemar)\ +๐Ÿช Support on [Ko-fi](https://ko-fi.com/heyValdemar)\ +๐Ÿ’– Support on [PayPal](https://www.paypal.com/paypalme/heyValdemarCOM) diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..58bfe34 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail + +# Start Ollama +/bin/ollama serve & +pid=$! + +# Wait for Ollama to be ready using Bash's built-in networking capabilities +while ! timeout 1 bash -c "echo > /dev/tcp/localhost/11434" 2>/dev/null; do + echo "Waiting for Ollama to start..." + sleep 1 +done +echo "Ollama started." + +# Retrieve and install/update models from the MODELS environment variable +IFS=',' read -ra model_array <<< "$MODELS" +for model in "${model_array[@]}"; do + echo "Installing/Updating model $model..." + ollama pull $model # This command fetches the latest version of the model +done +echo "All models installed/updated." + +# Continue to main process +wait $pid diff --git a/ollama-traefik-letsencrypt-docker-compose.yml b/ollama-traefik-letsencrypt-docker-compose.yml new file mode 100644 index 0000000..43d2551 --- /dev/null +++ b/ollama-traefik-letsencrypt-docker-compose.yml @@ -0,0 +1,179 @@ +# Ollama with Let's Encrypt Using Docker Compose + +# The complete installation guide is available on my website https://www.heyvaldemar.com/install-ollama-using-docker-compose/ + +# Change variables in the `.env` to meet your requirements. +# Note that the `.env` file should be in the same directory as `ollama-traefik-letsencrypt-docker-compose.yml`. + +# Create networks for your services before deploying the configuration using the commands: +# `docker network create traefik-network` +# `docker network create ollama-network` + +# Deploy Ollama using Docker Compose: +# `docker compose -f ollama-traefik-letsencrypt-docker-compose.yml -p ollama up -d` + +# Author +# Iโ€™m Vladimir Mikhalev, the Docker Captain, but my friends can call me Valdemar. +# https://www.docker.com/captains/vladimir-mikhalev/ + +# My website with detailed IT guides: https://www.heyvaldemar.com/ +# Follow me on YouTube: https://www.youtube.com/channel/UCf85kQ0u1sYTTTyKVpxrlyQ?sub_confirmation=1 +# Follow me on Twitter: https://twitter.com/heyValdemar +# Follow me on Instagram: https://www.instagram.com/heyvaldemar/ +# Follow me on Threads: https://www.threads.net/@heyvaldemar +# Follow me on Mastodon: https://mastodon.social/@heyvaldemar +# Follow me on Bluesky: https://bsky.app/profile/heyvaldemar.bsky.social +# Follow me on Facebook: https://www.facebook.com/heyValdemarFB/ +# Follow me on TikTok: https://www.tiktok.com/@heyvaldemar +# Follow me on LinkedIn: https://www.linkedin.com/in/heyvaldemar/ +# Follow me on GitHub: https://github.com/heyvaldemar + +# Communication +# Chat with IT pros on Discord: https://discord.gg/AJQGCCBcqf +# Reach me at ask@sre.gg + +# Give Thanks +# Support on GitHub: https://github.com/sponsors/heyValdemar +# Support on Patreon: https://www.patreon.com/heyValdemar +# Support on BuyMeaCoffee: https://www.buymeacoffee.com/heyValdemar +# Support on Ko-fi: https://ko-fi.com/heyValdemar +# Support on PayPal: https://www.paypal.com/paypalme/heyValdemarCOM + +networks: + traefik-network: + external: true + ollama-network: + external: true + +volumes: + webui-data: + ollama-data: + traefik-certificates: + +services: + webui: + image: ${WEBUI_IMAGE_TAG} + volumes: + - webui-data:/app/backend/data + environment: + OLLAMA_BASE_URL: http://ollama:11434 + networks: + - ollama-network + - traefik-network + extra_hosts: + - host.docker.internal:host-gateway + healthcheck: + test: timeout 10s bash -c ':> /dev/tcp/127.0.0.1/8080' || exit 1 + interval: 10s + timeout: 5s + retries: 3 + start_period: 90s + labels: + - "traefik.enable=true" + - "traefik.http.routers.webui.rule=Host(`${OLLAMA_HOSTNAME}`)" + - "traefik.http.routers.webui.service=webui" + - "traefik.http.routers.webui.entrypoints=websecure" + - "traefik.http.services.webui.loadbalancer.server.port=8080" + - "traefik.http.routers.webui.tls=true" + - "traefik.http.routers.webui.tls.certresolver=letsencrypt" + - "traefik.http.services.webui.loadbalancer.passhostheader=true" + - "traefik.http.routers.webui.middlewares=compresstraefik" + - "traefik.http.middlewares.compresstraefik.compress=true" + - "traefik.docker.network=traefik-network" + restart: unless-stopped + depends_on: + ollama: + condition: service_healthy + traefik: + condition: service_healthy + + ollama: + image: ${OLLAMA_IMAGE_TAG} + entrypoint: ["/usr/bin/bash", "/entrypoint.sh"] + volumes: + - ollama-data:/root/.ollama + - ./entrypoint.sh:/entrypoint.sh + environment: + MODELS: ${OLLAMA_INSTALL_MODELS} + networks: + - ollama-network + - traefik-network + # Uncomment to enable NVIDIA GPU support + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: ${OLLAMA_GPU_COUNT} + # capabilities: [gpu] + healthcheck: + test: ["CMD", "ollama", "--version"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + labels: + - "traefik.enable=true" + - "traefik.tcp.routers.ollama.rule=HostSNI(`*`)" + - "traefik.tcp.routers.ollama.service=ollama" + - "traefik.tcp.routers.ollama.entrypoints=ollama" + - "traefik.tcp.services.ollama.loadbalancer.server.port=11434" + - "traefik.docker.network=traefik-network" + restart: unless-stopped + depends_on: + traefik: + condition: service_healthy + + traefik: + image: ${TRAEFIK_IMAGE_TAG} + command: + - "--log.level=${TRAEFIK_LOG_LEVEL}" + - "--accesslog=true" + - "--api.dashboard=true" + - "--api.insecure=true" + - "--ping=true" + - "--ping.entrypoint=ping" + - "--entryPoints.ping.address=:8082" + - "--entryPoints.web.address=:80" + - "--entryPoints.websecure.address=:443" + - "--entryPoints.ollama.address=:11434" + - "--providers.docker=true" + - "--providers.docker.endpoint=unix:///var/run/docker.sock" + - "--providers.docker.exposedByDefault=false" + - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" + - "--certificatesresolvers.letsencrypt.acme.email=${TRAEFIK_ACME_EMAIL}" + - "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/acme.json" + - "--metrics.prometheus=true" + - "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0" + - "--global.checkNewVersion=true" + - "--global.sendAnonymousUsage=false" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - traefik-certificates:/etc/traefik/acme + networks: + - traefik-network + ports: + - "80:80" + - "443:443" + healthcheck: + test: ["CMD", "wget", "http://localhost:8082/ping","--spider"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 5s + labels: + - "traefik.enable=true" + - "traefik.http.routers.dashboard.rule=Host(`${TRAEFIK_HOSTNAME}`)" + - "traefik.http.routers.dashboard.service=api@internal" + - "traefik.http.routers.dashboard.entrypoints=websecure" + - "traefik.http.services.dashboard.loadbalancer.server.port=8080" + - "traefik.http.routers.dashboard.tls=true" + - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" + - "traefik.http.services.dashboard.loadbalancer.passhostheader=true" + - "traefik.http.routers.dashboard.middlewares=authtraefik" + - "traefik.http.middlewares.authtraefik.basicauth.users=${TRAEFIK_BASIC_AUTH}" + - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)" + - "traefik.http.routers.http-catchall.entrypoints=web" + - "traefik.http.routers.http-catchall.middlewares=redirect-to-https" + - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" + restart: unless-stopped