Skip to main content
Now that you have op-deployer configured, it’s time to spin up the sequencer for your rollup. This involves running both op-geth and op-node to create a functioning sequencer.
Step 2 of 5: This tutorial builds on Spin up op-deployer. Make sure you’ve completed that first.

What you’ll set up

The sequencer node consists of two core components:
  • op-geth: Execution layer that processes transactions and maintains state
  • op-node: Consensus layer that orders transactions and creates L2 blocks
The sequencer is responsible for:
  • Ordering transactions from users
  • Building L2 blocks
  • Signing blocks on the P2P network

Software installation

For spinning up a sequencer, we recommend using Docker, as it provides a simpler setup and consistent environment. In this guide, building from source is also provided as an alternative for those who need more control and easier debugging.
  • Use docker
  • Build from source
1

Set up directory structure and copy configuration files

If you prefer containerized deployment, you can use the official Docker images, and do the following:
# Create your sequencer directory inside rollup
cd ../    # Go back to rollup directory if you're in deployer
mkdir sequencer
cd sequencer

# Copy configuration files from deployer
cp ../deployer/.deployer/genesis.json .
cp ../deployer/.deployer/rollup.json .

# Generate JWT secret
openssl rand -hex 32 > jwt.txt
chmod 600 jwt.txt
2

Create environment variables file

# Create .env file with your actual values
cat > .env << 'EOF'
# L1 Configuration - Replace with your actual RPC URLs
L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY
L1_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com

# Private keys - Replace with your actual private key
PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY

# P2P configuration - Replace with your actual public IP
# Run `curl ifconfig.me` in a separate shell to obtain the value, then paste it below 
P2P_ADVERTISE_IP=YOUR_ACTUAL_PUBLIC_IP

EOF
Important: Replace ALL placeholder values (YOUR_ACTUAL_*) with your real configuration values.
3

Make sure your docker application is running

Create a docker-compose.yml file in the same directory:
services:
  op-geth:
    image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101511.1
    volumes:
      # Mount entire directory to avoid file mounting issues
      - .:/workspace
    working_dir: /workspace
    ports:
      - "8545:8545"
      - "8546:8546"
      - "8551:8551"
    command:
      - "--datadir=/workspace/op-geth-data"
      - "--http"
      - "--http.addr=0.0.0.0"
      - "--http.port=8545"
      - "--ws"
      - "--ws.addr=0.0.0.0"
      - "--ws.port=8546"
      - "--authrpc.addr=0.0.0.0"
      - "--authrpc.port=8551"
      - "--authrpc.jwtsecret=/workspace/jwt.txt"
      - "--syncmode=full"
      - "--gcmode=archive"
      - "--rollup.disabletxpoolgossip=true"
      - "--rollup.sequencerhttp=http://op-node:8547"
      - "--http.vhosts=*"
      - "--http.corsdomain=*"
      - "--http.api=eth,net,web3,debug,txpool,admin"
      - "--ws.origins=*"
      - "--ws.api=eth,net,web3,debug,txpool,admin"
      - "--authrpc.vhosts=*"

  op-node:
    image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:v1.13.5
    depends_on:
      - op-geth
    volumes:
      - .:/workspace
    working_dir: /workspace
    ports:
      - "8547:8547"
      - "9222:9222"
    environment:
      - L1_RPC_URL=${L1_RPC_URL}
      - L1_BEACON_URL=${L1_BEACON_URL}
      - PRIVATE_KEY=${PRIVATE_KEY}
      - P2P_ADVERTISE_IP=${P2P_ADVERTISE_IP}
    command:
      - "op-node"
      - "--l1=${L1_RPC_URL}"
      - "--l1.beacon=${L1_BEACON_URL}"
      - "--l2=http://op-geth:8551"
      - "--l2.jwt-secret=/workspace/jwt.txt"
      - "--rollup.config=/workspace/rollup.json"
      - "--sequencer.enabled=true"
      - "--sequencer.stopped=false"
      - "--sequencer.max-safe-lag=3600"
      - "--verifier.l1-confs=4"
      - "--p2p.listen.ip=0.0.0.0"
      - "--p2p.listen.tcp=9222"
      - "--p2p.listen.udp=9222"
      - "--p2p.advertise.ip=${P2P_ADVERTISE_IP}"
      - "--p2p.advertise.tcp=9222"
      - "--p2p.advertise.udp=9222"
      - "--p2p.sequencer.key=${PRIVATE_KEY}"
      - "--rpc.addr=0.0.0.0"
      - "--rpc.port=8547"
      - "--rpc.enable-admin"
      - "--log.level=info"
      - "--log.format=json"
4

Initialize op-geth with Docker

# Make sure you're in the rollup/sequencer directory with all files copied
cd rollup/sequencer

# Initialize op-geth using Docker
docker run --rm \
  -v $(pwd):/workspace \
  -w /workspace \
  us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101511.1 \
  init --datadir=./op-geth-data --state.scheme=hash ./genesis.json
5

Start the services

# Start both services
docker-compose up -d

# View logs
docker-compose logs -f
6

Final directory structure

rollup/
├── deployer/              # From previous step
   └── .deployer/         # Contains genesis.json and rollup.json
└── sequencer/             # You are here
    ├── jwt.txt            # Generated JWT secret
    ├── genesis.json       # Copied from deployer
    ├── rollup.json        # Copied from deployer
    ├── .env               # Environment variables
    ├── docker-compose.yml # Docker configuration
    ├── opnode_discovery_db/ # Created by Docker
    ├── opnode_peerstore_db/ # Created by Docker
    └── op-geth-data/      # Created by Docker
        ├── geth/          # Geth data
        └── keystore/      # Key files
Your sequencer node is now operational and ready to process transactions.

What’s Next?

Great! Your sequencer is running and processing transactions. The next step is to set up the batcher to publish transaction data to L1.

Spin up batcher →

Next: Configure and start op-batcher to publish L2 transaction data to L1 for data availability.

Need Help?

I