Skip to content

Containers Up! a web based platform designed to manage and update containers

License

Notifications You must be signed in to change notification settings

DigitallyRefined/containers-up

Repository files navigation

Containers Up!

Build and push workflow Container registry Container registry

Containers Up! is a web-based container management platform designed to simplify the administration of containers across multiple remote hosts.

It provides a unified interface for managing containerized applications, and automating updates with minimal manual intervention.

Key Features

  • πŸ–₯️ Multi-Host Management: Manage containers on multiple hosts via SSH connections
  • πŸŽ›οΈ Granular Control:
    • πŸ“¦ Control stacks/services via compose files
    • 🐳 Manage individual containers
    • πŸ–ΌοΈ Container image management
    • πŸ“‘ Container log viewer
    • πŸ—‘οΈ Cleanup of unused images
  • πŸ”„ Automated Updates: Container updates via GitHub webhooks (via Dependabot pull requests) & image tag updates via a schedule
  • πŸ“© Notifications: When a new Dependabot PR is created or a new container image is available (via Apprise)
  • 🌐 Service Discovery: Display web app icons and URLs (via existing Traefik labels)
  • 🧹 Resource Management: Cleanup of older images
  • πŸ“± Responsive Design: Works seamlessly on desktop and mobile devices
  • πŸŒ“ Modern UX: Automatic light and dark mode (based on system settings)
  • πŸ“Š Job Tracking: Monitor update jobs with detailed logs and retry capabilities
  • πŸ” Security: Secure SSH connections, webhook signature verification and OIDC authentication

Screenshot

screenshot

Installation

The app can be started using the following compose.yml:

services:
  containers-up:
    # https://github.com/DigitallyRefined/containers-up/releases
    image: ghcr.io/digitallyrefined/containers-up:1.1.0
    restart: unless-stopped
    ports:
      - 3000:3000
      - 3001:3001
    volumes:
      - ./storage:/storage
      - ./storage/.ssh:/root/.ssh
      - ./storage/.docker:/root/.docker

Open http://localhost:3000 to set up a new host. Set a name, SSH host and private key to display a dashboard of running composed containers, individual containers, images and actions.

Optional system wide configuration can be changed by copying .env.default to .env and adding env_file: ./.env to the compose file.

compose.yml example with HTTPS & OIDC authentication (via Pocket ID & Traefik)
  1. See Simple HTTPS Traefik Tutorial and Pocket ID walkthrough
services:
  containers-up:
    # https://github.com/DigitallyRefined/containers-up/releases
    image: ghcr.io/digitallyrefined/containers-up:1.1.0
    restart: unless-stopped
    volumes:
      - ./containers-up/storage:/storage
      - ./containers-up/storage/.ssh:/root/.ssh
      - ./containers-up/storage/.docker:/root/.docker
    env_file:
      - ./.env # < Create this file based on the .env.default instructions
    networks:
      - traefik
    labels:
      traefik.enable: true

      traefik.http.routers.containers-up.entrypoints: websecure
      traefik.http.routers.containers-up.rule: Host(`containers-up.example.com`) # < Update this
      traefik.http.routers.containers-up.tls: true
      traefik.http.routers.containers-up.tls.certresolver: production-cloudflare-dns
      traefik.http.routers.containers-up.service: containers-up
      traefik.http.services.containers-up.loadbalancer.server.port: 3000

      traefik.http.routers.containers-up-webhook.entrypoints: websecure
      traefik.http.routers.containers-up-webhook.rule: Host(`containers-up.example.com`) && PathPrefix(`/api/webhook`) # < Update this
      traefik.http.routers.containers-up-webhook.tls: true
      traefik.http.routers.containers-up-webhook.tls.certresolver: production-cloudflare-dns
      traefik.http.routers.containers-up-webhook.service: containers-up-webhook
      traefik.http.services.containers-up-webhook.loadbalancer.server.port: 3001

  pocket-id:
    # https://github.com/pocket-id/pocket-id/releases
    image: ghcr.io/pocket-id/pocket-id:v1.13.1
    restart: unless-stopped
    volumes:
      - './pocket-id/data:/app/data'
    environment:
      - APP_URL=https://id.example.com # < Update this
      - TRUST_PROXY=true
    networks:
      - 'traefik'
    labels:
      traefik.enable: true
      traefik.http.routers.pocketid.entrypoints: websecure
      traefik.http.routers.pocketid.rule: Host(`id.example.com`) # < Update this
      traefik.http.routers.pocketid.tls: true
      traefik.http.routers.pocketid.tls.certresolver: production-cloudflare-dns

  traefik:
    # Check migration guide first: https://doc.traefik.io/traefik/master/migration/v3/
    # https://github.com/traefik/traefik/releases
    image: docker.io/traefik:3.5.0
    container_name: 'traefik'
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443' # To setup HTTPS see: https://www.youtube.com/watch?v=-hfejNXqOzA
    volumes:
      - ./traefik/config:/etc/traefik
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - 'traefik'

networks:
  traefik:
    external: true
  1. Create the network docker network create traefik and start the services docker compose up -d
  2. Once Traefik and Pocket ID are up and running, set up a new user via Pocket ID and optionally add them to an admin group
  3. In the Pocket ID admin account create a new OIDC client and set up the callback URL as https://containers-up.example.com/auth-callback* and optionally only allow the admin group
  4. In the Containers Up! .env file (see .env.default) uncomment the OIDC config section, add the URI of Pocket ID (without any trailing paths) then copy and paste the client ID and secret (JWKS certificate URL can be set manually if auto-discovery fails via OIDC_JWKS_URL)
  5. After restarting the app, accessing https://containers-up.example.com should now require you to login

Setting up automatic compose.yml updates via Dependabot

  1. Make sure that your Containers Up! instance is available online publicly via HTTPS, sharing only the webhook port 3001. E.g. via a Cloudflare Tunnel or a Docker Wireguard Tunnel

  2. Create a GitHub repository with your container compose.yml files

  3. Each of your compose.yml files must use the full image version (not :latest) to receive Dependabot updates

  4. Under the Settings > Actions, enable Allow all actions and reusable workflows and under Workflow permissions allow Read and write permissions

  5. In your repo add .github/dependabot.template.yml:

version: 2
enable-beta-ecosystems: true # Remove once docker-compose updates become stable
updates:
  - package-ecosystem: 'docker-compose'
    directory: '**/compose.yml' # change this based on if you call your files compose.yml or docker-compose.yml

  - package-ecosystem: 'github-actions'
    directory: '/'
  1. Create a .github/workflows/generate_dependabot.yml file with the following content:
name: Generate dependabot.yml

on:
  push:
    branches:
      - main
  repository_dispatch:
  workflow_dispatch:

jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Generate dependabot.yml
        uses: Makeshift/generate-dependabot-glob-action@master

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v7
  1. This will automatically create a PR that will create a GitHub action managed .github/dependabot.yml file, which will automatically be updated for each of your compose.yml files. If it doesn't, click Actions > Generate dependabot.yml > Run workflow

  2. Next edit your host in Containers Up! and add the working folder where your repo is checked out on your server and add your GitHub repo URL user/repo (without https://github.com/), generate a random webhook secret and click the ℹ️ info icon copy the base URL to the webhook

  3. Back on GitHub, go to Settings > Webhooks > Add webhook, add your public webhook domain and base URL (listed on the Containers Up! edit webhook info screen) and select application/json as the Content Type. Use the same random webhook secret from your repo settings and choose Let me select individual events > Pull requests

If everything has been set up correctly the next time Dependabot creates a PR to update a compose.yml file an update will also appear on the Containers Up! dashboard.

Environment variables

All environment variables are optional and can be set in the compose.yml file via an env_file: ./.env or using the environment: array. Environment variables starting with ENV_PUBLIC_ are also embedded in the public HTML output.

Key Description Default
COMPOSE_FILENAME The default compose file to look for in the folder (usually compose.yml or docker-compose.yml) compose.yml
APP_URL App URL to used by links in notifications
APPRISE_NOTIFICATION Apprise is used for container update notifications. See Apprise syntax, see: Apprise Supported Notifications syntax
SSH_CONTROL_PERSIST How long SSH connections should persist after last request 20m
ENV_PUBLIC_OIDC_ISSUER_URI OpenID Connect base URI Auth disabled
ENV_PUBLIC_OIDC_CLIENT_ID OpenID Connect client ID
OIDC_CLIENT_SECRET OpenID Connect client secret
OIDC_JWKS_URL Optional OpenID Connect JSON Web Key Set (file URL) Auto discovered
MAX_QUEUE_TIME_MINS Max time in minutes a queued update can wait for 10
LOG_LINES Number of previous log lines shown when viewing a containers logs 500
DOCKER_USERNAME Docker Hub username - used to check for image updates (use if rate limited by Docker)
DOCKER_TOKEN Docker Hub token
GHCR_USERNAME GitHub Container Registry username - used to check for image updates on GHCR (use if rate limited by GitHub)
GHCR_TOKEN GitHub Container Registry token
CONTAINER_REGISTRY_USERNAME Custom container image registry username
CONTAINER_REGISTRY_TOKEN Custom container image registry token

About

Containers Up! a web based platform designed to manage and update containers

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors 2

  •  
  •  

Languages