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 serverfails withErrno::EADDRINUSE: Address already in uselocalhost:3000shows old application or blank pagebin/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.Find and kill the process using port 3000:
- 2.```bash
- 3.# Find process on port 3000
- 4.lsof -i :3000
- 5.# OR
- 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.Kill all Rails and Puma processes:
- 2.```bash
- 3.# Kill all Ruby processes running Rails
- 4.pkill -f "rails server"
- 5.pkill -f "puma"
- 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.Use a different port temporarily:
- 2.```bash
- 3.# Start Rails on a different port
- 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.Fix Docker port conflicts:
- 2.```bash
- 3.# Find Docker container using port 3000
- 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.Add port check to development startup script:
- 2.```bash
- 3.#!/bin/bash
- 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 stopbefore switching branches - Add
.overmind.sockand.foreman.sockto.gitignore - Use tmux or separate terminal tabs for each project
- Consider using
bin/devwith Overmind for better process management - Set project-specific ports in
.envfiles to avoid conflicts between projects