惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
L
LINUX DO - 最新话题
C
Check Point Blog
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
J
Java Code Geeks
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
S
Security @ Cisco Blogs
IT之家
IT之家
T
The Exploit Database - CXSecurity.com
The GitHub Blog
The GitHub Blog
D
Docker
Engineering at Meta
Engineering at Meta
AWS News Blog
AWS News Blog
S
Security Affairs
U
Unit 42
P
Palo Alto Networks Blog
V
Visual Studio Blog
Y
Y Combinator Blog
D
DataBreaches.Net
Forbes - Security
Forbes - Security
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
Security Latest
Security Latest
aimingoo的专栏
aimingoo的专栏
Simon Willison's Weblog
Simon Willison's Weblog
A
Arctic Wolf
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hacker News: Front Page
博客园 - 司徒正美
博客园 - Franky
宝玉的分享
宝玉的分享
TaoSecurity Blog
TaoSecurity Blog
Latest news
Latest news
Scott Helme
Scott Helme
MongoDB | Blog
MongoDB | Blog
量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Using TMUX and tmuxinator for a better docker compose experience
Nathan Cook · 2026-05-02 · via DEV Community

This tutorial provides a practical introduction to TMUX and how you can use tmuxinator to easily set up terminal dashboards with logs and shell sessions for your docker compose projects.

After a (very) brief overview of basic TMUX commands, we'll look at using tmuxinator to more easily configure TMUX with YAML configuration files, and at the end we'll go over how to install and use TMUX plugins.

This tutorial was written for Linux or WSL users (I'm running Ubuntu).

(Example repo)

Article Index

The Pitch

Instead of looking at a concantenated dump of service logs when you start a docker compose project, and needing to open separate terminals to run commands like docker compose logs and docker compose exec

Wouldn't it be nicer to see a dashboard with panes for each service's logs, with the ability to configure additional windows with separate panes for service SHELL sessions and whatever else:

Fortunately, it's fairly easy to set up such dashboards with TMUX and tmuxinator.

Install necessary packages

  • TMUX

    • sudo apt update && sudo apt install tmux
  • tmuxinator

    • To install the latest version of tmuxinator:
    • To install a usually slightly-out-of-date version of tmuxinator (which is probably just fine for this tutorial):
      • sudo apt update && sudo apt install tmuxinator

TMUX command basics

As the end-goal here is to show how to use tmuxinator .yaml configs to create bespoke dashboards for docker compose projects, I'm only going to go over the following:

  1. The TMUX prefix combo + keybinding system
  2. How to show the list of TMUX keybindings within TMUX
  3. How to detach from a TMUX session (leaving the session running)
  4. How to kill a TMUX session

The first thing to know about TMUX is that the standard commands all follow a "prefix" key combination.

The default prefix is Ctrl + b, but when we get to configuring TMUX with the ~/.tmux.config file, we'll be changing this to the more conveniet combo 'Ctrl + a'.

If you want to follow along for the rest of this section, run tmux in your terminal to start a session.

How to show the list of TMUX keybindings

Enter the prefix Ctrl + b, and then press ? (shift key is necessary) to see the list of keybindings.

Press ESC to close the list.

How to detach from a TMUX session

Enter the prefix Ctrl + b, and then enter d. This will detach the current TMUX session and return you to the command line.

To see a list of running TMUX sessions (from the command line), enter tmux ls.

To stop the currently running TMUX session, type tmux kill-session

How to open the 'command prompt' in TMUX and kill the current session and exit TMUX

Back in TMUX, enter the prefix Ctrl + b and then : (shift key necessary).

This opens a command prompt at the bottom of the screen, where you can run TMUX cli commands (like 'kill-session', for example).

Pressing 'ESC" will close the command prompt.

Configuring TMUX with the ~/.tmux.config file

Assuming you don't already have a tmux config file, create a file named .tmux.config in your home directory and paste the following into it:

# Turn on mouse input
set -g mouse on

# Increase the scrollback limit from 2000 to 10000
set -g history-limit 10000

# Change TMUX prefix key combo from 'Ctrl + b' to 'Ctrl + a'
set -g prefix C-a
unbind C-b
bind C-a send-prefix

# Add keybinding to change the currently focused pane with Alt + direction key
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D

# Add keybinding to select windows with 'Alt + Shift + Right' (next window) or 'Alt + Shift + Left' (previous window).
bind -n S-M-Right select-window -n
bind -n S-M-Left select-window -p

# Add Keybinding to kill the current tmux session and exit tmux with 'Ctrl + Shift + x'
bind -n C-S-x kill-session

# Add keybinding to clear focused pane (that is, the whole scrollback history) with 'Ctrl + Shift + k'
bind -n C-S-k send-keys -R \; clear-history

# Minor futzing around with the layout
set -g status-position bottom
set -g status-justify left

# Set what appears in the lower left
set -g status-left ''
set -g status-left-length 15

# Set what appears in the lower right
set -g status-right '%Y-%m-%d %H:%M '
set -g status-right-length 50

# Give windows reasonable titles
setw -g window-status-current-format ' #I #W #F '

# Give panes reasonable titles
set -g pane-border-status top
set -g pane-border-format '#[bold]#{pane_title}#[default]'

Enter fullscreen mode Exit fullscreen mode

Summary

  1. Mouse mode* is turned on
  2. Scrollback (history) limit is increased
  3. The TMUX prefix is changed from Ctrl + b to Ctrl + a
  • (you do not need to enter prefix before the following shortcuts:)
  1. Alt + Direction Key -- changes panes
  2. Alt + Shift + Left/Right Key -- changes windows
  3. Ctrl + Shift + x -- kills the current session, exiting TMUX
  4. Ctrl + Shift + k -- Clears the currently activce pane (as well as scrollback history)

* Mouse mode gives you

  • Mouse-wheel vertical scrolling
  • Select Panes by clicking on them
  • Resize Panes by click-dragging their borders
  • Select Windows by clicking their name in the bottom left of the status bar
  • A right-click menu with some common pane actions.
  • You can also copy text to the clipboard by click-dragging to select, but it's a little wonky.

Configuring TMUX in .yaml with tmuxinator

For the remainder of this article I will be referring to this example repo: docker-tmux-tutorial

If you clone the repo and CD into the directory like so

$ git clone https://github.com/moofoo/docker-tmux-tutorial.git && cd docker-tmux-tutorial

Enter fullscreen mode Exit fullscreen mode

You should see the following files/directories:

|- apps
|  |- web
|  |- api
|- db
|  |- 01_schema.sql
|  |- 02_data.sql
|- .tmuxinator.watch.yml
|- .tmuxinator.yml
|- docker-compose.watch.yml
|- docker-compose.yml
|- Dockerfile
|- README.md
|- tmux.config.example
|- tmux.sh

Enter fullscreen mode Exit fullscreen mode

If you then run (in the repo directory)

$ tmuxinator start

Enter fullscreen mode Exit fullscreen mode

the docker compose project will build (if it needs to) and TMUX will open showing windows and panes per the ./tmuxinator.yml config file.

Let's look at ./tmuxinator.yml now:

# ./.tmuxinator.yml

name: tmuxinator_tut
root: ./

on_project_start: docker compose up --wait -d

on_project_exit: docker compose stop

windows:
  - logs:
      panes:
        - web: clear && docker compose logs --since=1s -f web

        - api: clear && docker compose logs --since=1s -f api

        - db: clear && docker compose logs --since=15s -f db

        - red: clear && docker compose logs --since=15s -f redis

  - shell:
      panes:
        - web: clear && docker compose exec -w /usr/src/app web sh

        - api: clear && docker compose exec -w /usr/src/app api sh

        - psql: clear && docker compose exec db psql -U postgres -d tutorial_db

        - nestjs_repl: clear && docker compose exec -w /usr/src/app api npm run repl

  - home:
      layout: main-vertical
      panes:
        - home: clear

Enter fullscreen mode Exit fullscreen mode

Going over each section of this config file from the top:

name: tmuxinator_tut
root: ./

Enter fullscreen mode Exit fullscreen mode

The fields above set the tmux session name and tells tmuxinator to run commands in the current directory.

on_project_start: docker compose up --wait -d

on_project_exit: docker compose stop

Enter fullscreen mode Exit fullscreen mode

The "on_project_start" config tells tmuxinator to run docker compose up in detached mode when it starts.

The "on project*exit" config tells it to run docker compose stop when the session ends. (In other words, if you enter the "Ctrl + Shift + x" shortcut combo we previously configured in ~/.tmux.config, it will end the TMUX session and stop the docker compose project).

windows:
...rest

Enter fullscreen mode Exit fullscreen mode

The windows: option starts the block where you define the windows and panes you want in the TMUX session.

Here's the first window from the example:

- logs:
    panes:
      - web: clear && docker compose logs --since=1s -f web

      - api: clear && docker compose logs --since=1s -f api

      - db: clear && docker compose logs --since=15s -f db

      - red: clear && docker compose logs --since=15s -f redis

Enter fullscreen mode Exit fullscreen mode

This window definition creates a window named "logs", which has four panes showing the result of running docker compose logs for the web, api, db, and redis services.

- shell:
    panes:
      - web: clear && docker compose exec -w /usr/src/app web sh

      - api: clear && docker compose exec -w /usr/src/app api sh

      - psql: clear && docker compose exec db psql -U postgres -d tutorial_db

      - nestjs_repl: clear && docker compose exec -w /usr/src/app api npm run repl

Enter fullscreen mode Exit fullscreen mode

This window definition creates a window named "shell", with the following panes making use of docker compose exec:

  1. "web": Opens a shell to the working_dir of the "web" service.
  2. "api": Opens a shell to the working_dir of the "api" service.
  3. "psql": Starts a PSQL terminal session in the "db" service.
  4. "nestjs_repl": Starts the NestJS REPL for the NestJS server running in the "api" service.
- home:
    layout: main-vertical
    panes:
      - home: clear

Enter fullscreen mode Exit fullscreen mode

Just for convenience, this window definition opens your command line on the current (actual) directory.

If you want to see how this dashboard would be created with TMUX commands, check out the tmux.sh script

Extending TMUX with the Tmux Plugin Manager

The TMUX Plugin Manager provides a (relatively) painless way to extend TMUX functionality.

The following instructions will walk you through setting up TPM and installing/configuring the tmux-prefix-highlight plugin, which simply lets you display an indicator after you press the TMUX prefix combo.

1. Install the Tmux Plugin Manager

Run git clone as below to create the necessary files in your $HOME directory:

git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

Enter fullscreen mode Exit fullscreen mode

2. Edit your ~/.tmux.config file to use the plugin

At the top of the ~/.tmux.config before anything else, add the line:

set -g @plugin 'tmux-plugins/tmux-prefix-highlight'

Enter fullscreen mode Exit fullscreen mode

(follow the above pattern for all plugins)

Then, at the very bottom of ~/.tmux.config (after everything else), add the line:

run '~/.tmux/plugins/tpm/tpm'

Enter fullscreen mode Exit fullscreen mode

2. Configure/use the plugin

This plugin gives TMUX a new template string, #{prefix_highlight}. Assuming you've been following this tutorial, change the following line (35 for me) from

set -g status-left ''

Enter fullscreen mode Exit fullscreen mode

to

set -g status-left '#{prefix_highlight}'

Enter fullscreen mode Exit fullscreen mode

You can also add the following lines anywhere before the first and last lines in the file to also show an indicator when you're in "Copy mode":

# Tmux prefix highlight settings
set -g @prefix_highlight_show_copy_mode 'on'

Enter fullscreen mode Exit fullscreen mode

After making all the changes listed above, your ~/.tmux.config file should look something like this:

# Install Plugins
set -g @plugin 'tmux-plugins/tmux-prefix-highlight'

# Tmux prefix highlight settings
set -g @prefix_highlight_show_copy_mode 'on'

# Turn on mouse input
set -g mouse on

# Change TMUX prefix key combo from Ctrl-b to Ctrl-a
set -g prefix C-a
unbind C-b
bind C-a send-prefix

# Add keybinding to change the focused pane with Alt + direction key
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D

# Add keybinding to select windows with Alt+Shift+Right (next window) or Alt+Shift+Left (previous window).
bind -n S-M-Right select-window -n
bind -n S-M-Left select-window -p

# Add Keybinding to kill the current tmux session and exit tmux with Ctrl+Shift+x
bind -n C-S-x kill-session

# Add keybinding to clear the focused pane with Ctrl+Shift+k
bind -n C-S-k send-keys -R \; clear-history

# Minor futzing around with the layout
set -g status-position bottom
set -g status-justify left

# Set what appears in the lower left
set -g status-left '#{prefix_highlight}'
set -g status-left-length 15

# Set what appears in the lower right
set -g status-right '#[bold]%Y-%m-%d %H:%M#[default] '
set -g status-right-length 50

# Give windows reasonable titles
setw -g window-status-current-format ' #[bold]#I #W #F#[default] '

# Give panes reasonable titles
set -g pane-border-status top
set -g pane-border-format '#[bold]#{pane_title}#[default]'

# Run TMUX with the installed plugins
run '~/.tmux/plugins/tpm/tpm'

Enter fullscreen mode Exit fullscreen mode

Resources and Links

TMUX Cheat sheets

tmuxcheatsheet.com

tmux-cheatsheet.markdown

TMUX Cheatsheet

Plugins

TMUX Plugin Manager (TPM)

List of TPM plugins

Docs and Other

TMUX Man Page

TMUX Wiki - Getting Started

Awesome Tmux

A guide to customizing your TMUX config

Extra: Considerations when using docker compose develop 'watch' functionality

If you're making use of "Compose Watch" functionality in your docker-compose.yml file, you'll need to change your .tmuxinator.yml configuration. This is because docker compose up cannot run detached while in 'watch' mode.

See docker-compose.watch.yml and .tmuxinator.watch.yml in the example repo.

You can try out the 'watch' docker compose/tmuxinator config by running

tmuxinator start -p .tmuxinator.watch.yml

Enter fullscreen mode Exit fullscreen mode

# ./.tmuxinator.watch.yml

name: tmuxinator_watch_tut
root: ./

# Don't run docker compose up on_project_start
# on_project_start: docker compose up --wait -d

on_project_exit: docker compose stop

windows:
  - logs:
      panes:
        # Need to sleep before running docker compose commands, so they run after `docker compose up --watch`
        - web:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml logs --since=1s -f watch_web
        - api:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml logs --since=1s -f watch_api
        - db:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml logs --since=15s -f watch_db
        - redis:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml logs --since=15s -f watch_redis
  - shell:
      panes:
        - web:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml exec -w /usr/src/app watch_web sh
        - api:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml exec -w /usr/src/app watch_api sh
        - psql:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml exec watch_db psql -U postgres -d tutorial_db
        - nestjs_repl:
            - sleep 1
            - clear && docker compose -f docker-compose.watch.yml exec -w /usr/src/app watch_api npm run repl

  - home:
      layout: main-vertical
      panes:
        - home: clear

    # Run docker compose up --watch in its own window
  - watch:
      layout: main-vertical
      panes:
        - watch: docker compose up --watch

Enter fullscreen mode Exit fullscreen mode

To Summarize:

  • Instead of running docker compose up in detached mode on_project_start, it's run in watch mode in its own window.
  • Because of the above change, docker compose logs/exec commands need to be delayed so that they run after the docker compose up --watch command.