Docker
Rails
Server
Containerization
DevOps

Rails server is still running in a new opened docker container

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

If a Rails server seems to be "still running" when you start what you think is a new Docker container, the cause is usually one of three things: you are not actually in a new container, an older container is still bound to the port, or a shared file such as tmp/pids/server.pid is making Rails think the old server is still alive. Containers feel isolated, but bind mounts, volumes, and Docker Compose service reuse can preserve state in ways that surprise people.

First confirm what is actually running

The first mistake is often assuming a new shell means a new container. In Docker, docker exec opens a shell inside an existing running container, while docker run creates a new one.

Check the active containers first.

bash
docker ps
docker compose ps

If the Rails service is already running, opening another shell with docker exec -it web bash does not create a fresh environment. It just joins the existing one where the server process may still be PID 1 or another live process.

Port binding can make the old server look like the new one

If an older container is still publishing port 3000, requests to localhost:3000 will keep hitting that old container even after you start another one.

bash
docker ps --format 'table {{.Names}}\t{{.Ports}}\t{{.Status}}'

If two containers try to use the same host port, Docker usually rejects the second bind. More often, the real confusion is that the old container never stopped, so the browser is still reaching it.

Rails often leaves a PID file in a shared mount

In development, a common Compose setup mounts the app directory from the host into the container. That means files under tmp can persist across container lifecycles. If tmp/pids/server.pid survives, Rails may refuse to start and report that a server is already running.

A typical fix is to remove the PID file before booting.

bash
rm -f tmp/pids/server.pid
bundle exec rails server -b 0.0.0.0

Many teams make this part of the container startup command.

yaml
command: bash -lc "rm -f tmp/pids/server.pid && bundle exec rails server -b 0.0.0.0"

That does not fix every container problem, but it does solve one of the most common Rails-in-Docker startup issues.

Named volumes and bind mounts preserve state on purpose

Docker containers are disposable, but mounted storage is not. If your Compose file mounts the project directory or a named volume, files created by the previous container can appear in the next one.

That is why a "new container" can still see:

  • old PID files
  • cached gems
  • socket files
  • development logs
  • temporary state under the mounted app directory

This is normal Docker behavior, not a leak between unrelated containers.

Rebuild versus recreate are different operations

Another source of confusion is the difference between rebuilding an image and recreating a container. docker compose build creates a new image layer set. It does not automatically remove old containers, volumes, or mounted files.

If you need a cleaner restart path, use commands that stop and recreate the service intentionally.

bash
docker compose down
docker compose up --build

If you also need to remove anonymous volumes, add the appropriate cleanup flags carefully. Do not remove volumes casually if they hold important data.

Logs tell you whether Rails is actually running

When the situation is unclear, inspect logs instead of guessing.

bash
docker compose logs web
docker logs container_name

If Rails failed on a PID file, port bind, or boot error, the logs will usually say so directly. That is faster than treating the problem as a Docker mystery.

Common Pitfalls

  • Using docker exec and assuming it created a new container.
  • Forgetting that an older container may still be serving the same host port.
  • Leaving tmp/pids/server.pid in a bind-mounted project directory.
  • Rebuilding the image without actually recreating the container.
  • Ignoring logs and trying to diagnose the issue only from browser behavior.

Summary

  • A truly new container can still see old state if files come from a bind mount or volume.
  • 'docker exec enters an existing container; it does not create a fresh one.'
  • Old containers bound to port 3000 can make it look like the new container is serving traffic.
  • Rails PID files under tmp/pids are a frequent cause of false "server already running" errors.
  • Use docker ps, Compose logs, and an explicit startup command that removes stale PID files.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.