To get the label positions on the first of each month, we use substr.
One way is to use two-month intervals as you have indicated. For this we may generate sequences 1, 2, 3, ... along the dates, using seq_along, and look where they are zero in modulo 2 to get the subset IDs ids. To get the month-year format we use format= (see ?strftime for options).
op <- par(mar=c(5, 5, 3, 7))  ## set par
plot(datereal, base9, type="l", lwd=2, col="blue", xaxt="n", xlab="Month",
     ylab="Daily new cases")
which(substr(datereal, 9, 10) == "01")
labs <- datereal[substr(datereal, 9, 10) == "01"]
ids <- seq_along(labs)[(seq_along(labs) + 1) %% 2 == 0]
axis.Date(1, at=labs[ids], format="%b %y", cex.axis=.9)
par(op)  ## reset par

Alternatively, you can rotate the text ninety degrees (but the first variant is nicer). This is possible using mtext. We still need axis to get the tick marks.
op <- par(mar=c(5, 5, 3, 7))
plot(datereal, base9, type="l", lwd=2, col="blue", xaxt="n", xlab="Month",
     ylab="Daily new cases")
axis(1, at=labs, labels=FALSE)
mtext(strftime(labs, format="%b %y"), side=1, line=.75, at=labs, las=2, cex=.8)
par(op)

Note, you appear to be working with the Plot window and saving images by mouse click. If you rescale the window, the labels may disappear. A better choice is to use, for example, the png device as explained in this answer
Data:
base9 <- 5e5*dnorm(seq(-2, 14, length=516), 10, 4)
datereal <- seq(as.Date("2020-02-01"), as.Date("2021-06-30"), "day")