Add Other Services to Your Project
Since Spin is based off of Docker Compose and Docker Swarm Mode, the possibilities are endless when it comes to expanding your infrastructure with Spin.
Important Notes
Every infrastructure configuration is unique and you should always prioritize security when applying configurations. Be sure to encrypt secrets where possible, but for demonstration purposes we will show you examples in plain text.
We make a few assumptions in our examples below:
- Your development network is called
development
and properly created in your Docker Compose file - You have the proper configurations made available in your
.infrastructure
folder with the.gitignore
properly configured
MariaDB
Example: docker-compose.yml
services:
mariadb:
image: mariadb:11.4
Example: docker-compose.dev.yml
services:
mariadb:
networks:
- development
volumes:
- ./.infrastructure/volume_data/mariadb/database_data/:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "rootpassword"
MYSQL_DATABASE: "laravel"
MYSQL_USER: "mysqluser"
MYSQL_PASSWORD: "mysqlpassword"
ports:
- "3306:3306"
networks:
development:
MeiliSearch
Example: docker-compose.yml
services:
meilisearch:
image: getmeili/meilisearch:v1.9
environment:
MEILI_NO_ANALYTICS: "true"
Example: docker-compose.dev.yml
services:
meilisearch:
environment:
MEILI_MASTER_KEY: "masterKey"
volumes:
- ./.infrastructure/volume_data/meilisearch/meilisearch_data:/meili_data:cached
networks:
- development
networks:
development:
MySQL
Example: docker-compose.yml
services:
mysql:
image: mysql:8.4
Example: docker-compose.dev.yml
services:
mysql:
networks:
- development
volumes:
- ./.infrastructure/volume_data/mysql/database_data/:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "rootpassword"
MYSQL_DATABASE: "laravel"
MYSQL_USER: "mysqluser"
MYSQL_PASSWORD: "mysqlpassword"
ports:
- "3306:3306"
networks:
development:
Node
Example: docker-compose.yml
services:
node:
image: node:20
working_dir: /usr/src/app
Example: docker-compose.dev.yml
services:
node:
command: "yarn dev"
volumes:
- .:/usr/src/app:cached
networks:
- development
ports:
- 3000:3000 # Remove the ports if you are using something like Trafeik or Caddy (recommended)
networks:
development:
Commands
You can see the "command:" calls to run yarn dev
. This may need to be changed, depending on your project (and if you are using npm or yarn). Feel free to remove this command if you prefer to run the commands manually.
Using with Traefik
The example above directly exposes the Node server on port 3000. You'll likely never do that in production. If you use something like Traefik, you would replace the ports with labels, like this:
Node Traefik Labels Example
labels:
- "traefik.enable=true"
- "traefik.http.routers.mynodeapp.rule=Host(`mynodeapp.dev.test`)"
- "traefik.http.routers.mynodeapp.entrypoints=websecure"
- "traefik.http.routers.mynodeapp.tls=true"
- "traefik.http.services.mynodeapp.loadbalancer.server.port=3000"
- "traefik.http.services.mynodeapp.loadbalancer.server.scheme=http"
The label
adds certain metadata to your container, telling Traefik to route "mynodeapp.dev.test" to port 3000 on your node container. All web traffic will enter through Traefik first, then to your Node container -- which is a more realistic scenario to what you can run in production.
PHP
We use our open source PHP Docker Images, which are based on the official PHP images, but production-ready by default and optimized for Laravel out of the box. Read our guide on selecting the right image variation for your project.
Notice how this project is using build
instead of just calling an image directly. See the Dockerfile
example why we do this.
Example: docker-compose.yml
services:
php:
build:
context: . # Look for Dockerfile in the project root
target: base
Example: docker-compose.dev.yml
services:
php:
build:
# Notice how our build calls the "development" target.
# See the Dockerfile for more details
target: development
args:
# Spin loads the UID and GID to match the host in development
# This is how we fix permission errors in development
USER_ID: ${SPIN_USER_ID}
GROUP_ID: ${SPIN_GROUP_ID}
volumes:
- .:/var/www/html/
ports:
- 80:80 # Remove the "ports" section if using Traefik or Caddy (recommended)
networks:
- development
networks:
development:
Example: Dockerfile
# Learn more about the Server Side Up PHP Docker Images at:
# https://serversideup.net/open-source/docker-php/
FROM serversideup/php:8.3-fpm-nginx AS base
FROM base AS development
# Fix permission issues in development by setting the "www-data"
# user to the same user and group that is running docker.
ARG USER_ID
ARG GROUP_ID
RUN docker-php-serversideup-set-id www-data ${USER_ID} ${GROUP_ID}
FROM base AS deploy
COPY --chown=www-data:www-data . /var/www/html
Using with Traefik
The docker-compose.yml examples above exposes the HTTP server on port 80. If you use something like Traefik, you would replace the ports with labels, like this:
Laravel Traefik Labels Example
labels:
- "traefik.enable=true"
- "traefik.http.routers.laravel.rule=HostRegexp(`laravel.dev.test`)"
- "traefik.http.routers.laravel.entrypoints=web"
- "traefik.http.services.laravel.loadbalancer.server.port=80"
- "traefik.http.services.laravel.loadbalancer.server.scheme=http"
Redis
Example: docker-compose.yml
services:
redis:
image: redis:7.2
Example: docker-compose.dev.yml
services:
redis:
command: "redis-server --appendonly yes --requirepass mysupersecretredispassword"
volumes:
- ./.infrastructure/volume_data/redis/data:/data
ports:
- "6379:6379"
networks:
- development
networks:
development:
Soketi
See the Soketi documentation for selecting the correct version.
Example: docker-compose.yml
services:
socket:
image: quay.io/soketi/soketi:1.6-16
Example: docker-compose.dev.yml
services:
socket:
environment:
DEBUG: '1'
DB_REDIS_HOST: "redis"
DB_REDIS_PASSWORD: "redispassword"
DB_REDIS_KEY_PREFIX: "socketi"
networks:
- development
networks:
development:
Using with Traefik
The docker-compose.yml examples above exposes the HTTP server on port 80. If you use something like Traefik, you would replace the ports with labels, like this:
Laravel Traefik Labels Example
labels:
- "traefik.enable=true"
- "traefik.http.routers.soketi.rule=HostRegexp(`soketi.dev.test`)"
- "traefik.http.routers.soketi.entrypoints=websecure"
- "traefik.http.routers.soketi.tls=true"
- "traefik.http.services.soketi.loadbalancer.server.port=6001"
- "traefik.http.services.soketi.loadbalancer.server.scheme=http"
Traefik
Traefik is a reverse proxy and is great for terminating SSL for any service that supports HTTP/HTTPS. Since Traefik is such an important service, there can be a little more configuration in order to get it to function well.
Example: docker-compose.yml
services:
traefik:
image: traefik:v3.1
Example: docker-compose.dev.yml
traefik:
networks:
development:
aliases:
- myapp.dev.test
ports:
- "80:80"
- "443:443"
volumes:
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./.infrastructure/conf/traefik/dev/traefik.yml:/traefik.yml:ro
- ./.infrastructure/conf/traefik/dev/traefik-certs.yml:/traefik-certs.yml
- ./.infrastructure/conf/traefik/dev/certificates/:/certificates
Example: Development configuration at `./.infrastructure/conf/traefik/dev/traefik.yml`
# Allow self-signed certificates
serversTransport:
insecureSkipVerify: true
providers:
docker:
exposedByDefault: false
file:
filename: /traefik-certs.yml
watch: true
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
accessLog: {}
log:
level: ERROR
api:
dashboard: true
insecure: true
Example: Development configuration at `./.infrastructure/conf/traefik/dev/traefik-certs.yml`
tls:
stores:
default:
defaultCertificate:
certFile: /certificates/local-dev.pem
keyFile: /certificates/local-dev-key.pem
certificates:
- certFile: /certificates/local-dev.pem
keyFile: /certificates/local-dev-key.pem
stores:
- default
Trusting self-signed certificates
If you use spin init
or spin new
to create your project, we ship a local-dev
keypair. This is signed by the Server Side Up Certificate Authority. If you'd like to trust this CA, you need to install the CA Root on your machine (only do this if you trust our process): https://serversideup.net/ca/.