I believe the issue is the width = 0.1
parameter, e.g.
library(tidyverse)
library(palmerpenguins)
penguins %>%
na.omit() %>%
select(species, island, bill_length_mm) %>%
ggplot(aes(x = island, y = bill_length_mm, fill = species)) +
geom_boxplot(width=.1) +
geom_violin()

If you make the widths the same they line up as expected:
library(tidyverse)
library(palmerpenguins)
penguins %>%
na.omit() %>%
select(species, island, bill_length_mm) %>%
ggplot(aes(x = island, y = bill_length_mm, fill = species)) +
geom_boxplot(width=.2) +
geom_violin(width=.2)

Also, instead of using boxplots and violins (both of illustrating the distribution of values) it might be better to plot the individual values and the distribution, e.g.
library(tidyverse)
library(palmerpenguins)
library(ggbeeswarm)
penguins %>%
na.omit() %>%
select(species, island, bill_length_mm) %>%
rename(Species = species, Island = island) %>%
ggplot(aes(x = Island, y = bill_length_mm, fill = Species)) +
geom_boxplot(width=.4, outlier.shape = NA,
position = position_dodge2(preserve = "single")) +
geom_quasirandom(aes(colour = Species), groupOnX = TRUE,
width=.2, alpha = 0.5, dodge.width = 0.4) +
theme_bw(base_size = 16) +
ylab("Bill Length (mm)")
