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)")
