Introduction

When starting a Rails development server with bin/rails server or bin/dev, the process fails with Address already in use - bind(2) for "0.0.0.0" port 3000. This happens because a previous Rails, Puma, or Foreman process was not properly terminated and still holds the port. The stale process may be a zombie process from a crashed terminal session, a backgrounded process, or a Docker container still running.

Symptoms

  • bin/rails server fails with Errno::EADDRINUSE: Address already in use
  • localhost:3000 shows old application or blank page
  • bin/dev (Foreman) fails to start web process
  • Hot reload not working because old server is still running
  • Spring still running but cannot connect to new server

Error output: `` => Booting Puma => Rails 7.1.3 application starting in development Puma starting in single mode... * Version 6.4.2 (ruby 3.2.2), codename: The Eagle of Durango * Min threads: 5, max threads: 5 * Environment: development * Listening on http://0.0.0.0:3000 Exiting Errno::EADDRINUSE: Address already in use - bind(2) for "0.0.0.0" port 3000

Common Causes

  • Previous Rails server process still running in background
  • Foreman/Overmind session not properly stopped
  • Docker container still running on port 3000
  • Another application (Skype, another dev server) using port 3000
  • Puma spawned child process that did not die with parent

Step-by-Step Fix

  1. 1.Find and kill the process using port 3000:
  2. 2.```bash
  3. 3.# Find process on port 3000
  4. 4.lsof -i :3000
  5. 5.# OR
  6. 6.sudo netstat -tlnp | grep 3000

# Example output: # COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME # ruby 12345 dev 10u IPv4 123456 0t0 TCP *:3000 (LISTEN)

# Kill the process kill 12345

# If it does not die, force kill kill -9 12345

# One-liner to kill whatever is on port 3000 lsof -ti:3000 | xargs kill -9 ```

  1. 1.Kill all Rails and Puma processes:
  2. 2.```bash
  3. 3.# Kill all Ruby processes running Rails
  4. 4.pkill -f "rails server"
  5. 5.pkill -f "puma"
  6. 6.pkill -f "foreman"

# Kill all Spring processes spring stop

# Verify nothing is left ps aux | grep -E "rails|puma|spring" | grep -v grep ```

  1. 1.Use a different port temporarily:
  2. 2.```bash
  3. 3.# Start Rails on a different port
  4. 4.bin/rails server -p 3001

# Or set PORT environment variable PORT=3001 bin/rails server

# For Foreman, change port in Procfile.dev # web: bin/rails server -p ${PORT:-3001} ```

  1. 1.Fix Docker port conflicts:
  2. 2.```bash
  3. 3.# Find Docker container using port 3000
  4. 4.docker ps --filter "publish=3000"

# Stop the container docker stop $(docker ps --filter "publish=3000" -q)

# Or remove stale containers docker-compose down docker-compose up -d ```

  1. 1.Add port check to development startup script:
  2. 2.```bash
  3. 3.#!/bin/bash
  4. 4.# bin/check-port

PORT=${PORT:-3000} PID=$(lsof -ti:$PORT 2>/dev/null)

if [ -n "$PID" ]; then echo "Port $PORT is in use by PID $PID" echo "Process: $(ps -p $PID -o comm=)" read -p "Kill it? (y/n) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then kill $PID echo "Killed process $PID" else echo "Starting on port $((PORT + 1)) instead" export PORT=$((PORT + 1)) fi fi ```

Prevention

  • Always stop Rails server with Ctrl+C before closing terminal
  • Use spring stop before switching branches
  • Add .overmind.sock and .foreman.sock to .gitignore
  • Use tmux or separate terminal tabs for each project
  • Consider using bin/dev with Overmind for better process management
  • Set project-specific ports in .env files to avoid conflicts between projects