Spin up sequencer
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 stateop-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.
If you prefer containerized deployment, you can use the official Docker images, and do the following:
Set up directory structure and copy configuration files
# 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
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.
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"
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
Start the services
# Start both services
docker-compose up -d
# View logs
docker-compose logs -f
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 during initialization
└── opnode_peerstore_db/ # Created by Docker during initialization
└── op-geth-data/ # Created by Docker during initialization
├── 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 →Need Help?
- Community Support: Join the Optimism Discord (opens in a new tab)
- Batcher Configuration: op-batcher Configuration Guide
- Best Practices: Chain Operator Best Practices