:marketing-hero :marketing-video :marketing-technologies :marketing-host :marketing-docker :marketing-built-for-pros :marketing-features :marketing-testimonials :marketing-built-in-public :marketing-pricing :marketing-faq # Activate your access ## Completing your purchase You can [purchase a license key](https://getspin.pro/#pricing) from the Spin Pro website. All purchases are handled through Lemon Squeezy. You'll receive an email with your receipt and license key. You'll need this license key to access the Spin Pro template. ## Activate Your License Key ::note Be sure to login with the correct GitHub Account. Once you activate with a GitHub account, you cannot change it. :: ::responsive-image --- maxWidth: 500 alt: Activate your license key src: https://getspin.pro/images/docs/activate.png --- :: To activate your license key, you'll need to visit {rel=""nofollow""}. You'll need to enter your license key found on your emailed receipt, where you'll be prompted to log in with your GitHub account. ## Ensure you have access to the Spin Pro repo ::note Be sure to activate GitHub invites immediately, otherwise the invite may expire. :: Our system will automatically send you an email to get access to the [Spin Pro repo](https://github.com/serversideup/spin-template-laravel-pro){rel=""nofollow""}. You'll need to accept the invite to access the repository. ## Configure your SSH Keys with GitHub Since this is a private repository, you'll need to ensure you have your SSH keys configured with GitHub. You can follow the instructions on GitHub to [add your SSH keys](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account){rel=""nofollow""}. You can test your SSH keys by running the following command: ```bash [Test your SSH keys with GitHub] ssh -T git@github.com ``` If you see your GitHub username returned, then you have properly configured your SSH access with GitHub. # Install to macOS ## Install Docker Desktop MacOS does not ship with Docker by default. To get Docker installed, you will need "Docker Desktop", which is the official desktop tool developed by Docker. [Learn how to install Docker Desktop →](https://docs.docker.com/desktop/mac/install/){rel=""nofollow""} ## Download and install `spin` Once Docker is installed, you are now ready to install `spin`. Run the installer with this simple command in your terminal. **No root permissions required.** ```bash [Install spin to your machine (no root permissions required)] bash -c "$(curl -fsSL https://raw.githubusercontent.com/serversideup/spin/main/tools/install.sh)" ``` The above script will install spin at the *user* level in `~/.spin`, using less than 300KB of storage. ::note Spin will prompt you if you want Spin to modify your PATH variable. If you press "Yes" follow the instructions on the screen. If you press "No" you will need to manually add Spin to your PATH. :: ## Configuring your PATH variable manually If you did not add `spin` to your PATH during the installation, you can manually add it to your PATH by adding this to your shell profile: ::note Run `echo $0` in your terminal to figure out which shell you are using. :: ```bash [Add spin to your path] # Add this to `~/.zshrc` or `~/.bash_profile` export PATH="$HOME/.spin/bin:$PATH" ``` In order to apply the changes to your current terminal session, you will need to run the `source` command. ```bash [Use the "source" command to apply your profile changes immediately] # If you're using ZSH source ~/.zshrc # If you're using Bash source ~/.bash_profile ``` ## Validate it's working You should be able to run this and get a result 🥳 ```bash [Confirm spin is working correctly by getting the version] spin version ``` # Install to Windows ## Prerequisites Spin requires a working Windows installation with Docker installed. There are two popular methods to install Docker on Windows: 1. Install `docker-ce` on Windows Subsystem Linux v2 (WSL2) *\[recommended]* 2. Install Docker Desktop on Windows with WSL2 backend ![Docker Installation Options](https://getspin.pro/images/docs/windows/docker-installation-options.png) #### Optional software You may want to consider installing this software to improve your development experience (this is what we use). - [Windows Terminal](https://docs.microsoft.com/en-us/windows/terminal/install){rel=""nofollow""} - This is a great terminal application that will give you tab support for your CLIs. ## Install Windows Subsystem Linux v2 (WSL2) Both options require installing WSL2. We can follow the principles discussed in the [official WSL2 documentation](https://docs.microsoft.com/en-us/windows/wsl/install){rel=""nofollow""} and prepare our machine to run "Windows Subsystem Linux v2" (WSL2). We prefer Ubuntu as our distribution. So if you're happy with that recommendation, run this command in PowerShell as administrator to install WSL2. ```bash [Install and use Ubuntu as your Windows Subsystem Linux distro] wsl --install -d ubuntu ``` ::note A restart may be required. :: ![WSL Install Command](https://getspin.pro/images/docs/windows/wsl-install.png) After a reboot, you may be prompted to create a username and password for your new Ubuntu installation. This is a separate user from your Windows user. ![WSL Create Username and Password](https://getspin.pro/images/docs/windows/wsl-configure.png) Once configured, you can confirm is working by opening a new PowerShell window and running: ```bash [Enter the Ubuntu shell] wsl ``` ::note ⚠️ Always be aware of what shell you're in (Windows or Ubuntu). You can always tell by the prompt. :: ### What a Windows shell looks like You can tell you're in a Windows shell by the prompt when you see the `PS` prefix and the `C:\` prefix. ![Windows Shell](https://getspin.pro/images/docs/windows/shell-windows.png) ### What a Linux shell looks like When you're in a Linux shell, you'll see the different colors and things like `/mnt/c` for your Windows drive. ![Linux Shell](https://getspin.pro/images/docs/windows/shell-linux.png) To go back to your Windows shell, type `exit` and press enter. ::note **⚠️ Always run `spin` from the Linux shell**. You'll need to run `wsl` from a Windows prompt to enter the Linux shell, then you can run `spin` after you complete the installation. :: ## OPTION 1: Install `docker-ce` within WSL2 (recommended) Installing `docker-ce` within Linux allows you to run the open source versions of Docker without installing any proprietary software. If this option interests you, run `wsl` to enter a Linux shell and then follow our instructions for installing Spin on Linux. [Install Docker Community Edition to Linux (WSL2) →](https://getspin.pro/docs/installation/install-linux) ## OPTION 2: Install Docker Desktop If you prefer to install Docker Desktop with the WSL2 backend, you'll need to [download Docker Desktop](https://www.docker.com/products/docker-desktop){rel=""nofollow""} from Docker's website. ### Installation Double click the setup file to begin the installation. ### Configuration If prompted, leave the default options checked. ![Docker Configuration](https://getspin.pro/images/docs/windows/docker-desktop-configuration.png) ::note Another restart may be required. :: After the installation completes, you may be prompted to reboot your machine. If so, go ahead and do that. ![Docker Reboot](https://getspin.pro/images/docs/windows/docker-reboot.png) ### Accept the terms Once your computer comes back online, click on the **Docker Desktop** icon. The application will initialize and be sure to accept the terms. ![Accept Docker EULA](https://getspin.pro/images/docs/windows/docker-accept-eula.png) ### Configuring your Docker Account You will be prompted to login to your Docker account. If you don't have one, you can create one for free. For most cases, you can use Docker without creating an account. ![Docker Login](https://getspin.pro/images/docs/windows/docker-login.png) ## Verify Docker Desktop ```bash [Validate Docker is working (run this in Windows Terminal)] docker info ``` It should return version information. ![Docker Info](https://getspin.pro/images/docs/windows/docker-info.png) ```bash [Run a simple container to ensure Docker is working] docker run --rm hello-world ``` It should return something like this. ![Docker Run Hello World!](https://getspin.pro/images/docs/windows/docker-run-hello-world.png) ## Download and install `spin` into WSL2 ::note ⚠️ Be sure to run `wsl` to enter the Linux shell before running the following commands. :: Run the installer with this simple command in your terminal ```bash [Install Spin (no root permissions required)] bash -c "$(curl -fsSL https://raw.githubusercontent.com/serversideup/spin/main/tools/install.sh)" ``` The above script will install spin at the *user* level in `~/.spin`, using less than 300KB of storage. ::note Spin will prompt you if you want Spin to modify your PATH variable. If you press "Yes" follow the instructions on the screen. If you press "No" you will need to manually add Spin to your PATH. :: ## Configuring your PATH variable manually If you did not add `spin` to your PATH during the installation, you can manually add it to your PATH by adding this to your shell profile: ::note Run `echo $0` in your terminal to figure out which shell you are using. :: ```bash [Add spin to your path] # Add this to `~/.zshrc` or `~/.bash_profile` export PATH="$HOME/.spin/bin:$PATH" ``` In order to apply the changes to your current terminal session, you will need to run the `source` command. ```bash [Use the "source" command to apply your profile changes immediately] # If you're using ZSH source ~/.zshrc # If you're using Bash source ~/.bash_profile ``` ## Validate it's working You should be able to run this and get a result 🥳 ```bash [Confirm spin is working correctly by getting the version] spin version ``` # Install to Linux ## Prerequisites You must have a working installation of Docker. ::note Most Docker documentation will push you to install "Docker Desktop" on your Linux machine. This is completely unnecessary in our opinion. Instead of "Docker Desktop", we suggest installing the "Docker Engine" instead. :: ### Install Docker Engine Install "Docker Engine" following the official installation instructions: - [CentOS](https://docs.docker.com/engine/install/centos/){rel=""nofollow""} - [Debian](https://docs.docker.com/engine/install/debian/){rel=""nofollow""} (NOT for Ubuntu. Go [here](https://docs.docker.com/engine/install/ubuntu/){rel=""nofollow""} for Ubuntu) - [Fedora](https://docs.docker.com/engine/install/fedora/){rel=""nofollow""} - [RHEL](https://docs.docker.com/engine/install/rhel/){rel=""nofollow""} - [SLES](https://docs.docker.com/engine/install/sles/){rel=""nofollow""} - [Ubuntu](https://docs.docker.com/engine/install/ubuntu/){rel=""nofollow""} - [Raspbian](https://docs.docker.com/engine/install/raspberry-pi-os/){rel=""nofollow""} - [Binaries](https://docs.docker.com/engine/install/binaries/){rel=""nofollow""} ### Configure Docker permissions Using the [post-installation instructions defined by Docker](https://docs.docker.com/engine/install/linux-postinstall/){rel=""nofollow""}, be sure to add your current user to the `docker` group if you want to be able to run Docker without root privileges. ```bash [Create the "docker" group] sudo groupadd docker ``` ```bash [Add your current user to the "docker" group.] sudo usermod -aG docker $USER ``` ```bash [Activate the changes to groups.] newgrp docker ``` ### Ensure Docker is working To test you have a working version of Docker, you can run their "hello world" container. `docker version`. ```bash [Run a "hello world" container to ensure Docker works correctly] docker run hello-world ``` ### Check your Docker Compose Version Spin is set to run the latest version of Docker Compose (Version 2). ```bash [Check your Docker Compose version] docker compose version ``` If you do not see version 2.x installed, you'll need to update. [How to Install Docker Compose V2 →](https://docs.docker.com/compose/cli-command/#install-on-linux){rel=""nofollow""} ## Download and install `spin` Run the installer with this simple command in your terminal ```bash [Install Spin (no root permissions required)] bash -c "$(curl -fsSL https://raw.githubusercontent.com/serversideup/spin/main/tools/install.sh)" ``` The above script will install spin at the *user* level in `~/.spin`, using less than 300KB of storage. ::note Spin will prompt you if you want Spin to modify your PATH variable. If you press "Yes" follow the instructions on the screen. If you press "No" you will need to manually add Spin to your PATH. :: ## Configuring your PATH variable manually If you did not add `spin` to your PATH during the installation, you can manually add it to your PATH by adding this to your shell profile: ::note Run `echo $0` in your terminal to figure out which shell you are using. :: ```bash [Add spin to your path] # Add this to `~/.zshrc` or `~/.bash_profile` export PATH="$HOME/.spin/bin:$PATH" ``` In order to apply the changes to your current terminal session, you will need to run the `source` command. ```bash [Use the "source" command to apply your profile changes immediately] # If you're using ZSH source ~/.zshrc # If you're using Bash source ~/.bash_profile ``` ## Validate it's working You should be able to run this and get a result 🥳 ```bash [Confirm spin is working correctly by getting the version] spin version ``` # Install via Composer ## Add `spin` to your project with Composer Installing `spin` at the project level is a great way to deploy `spin` without much configuration from the user's end. [View `spin` on Packagist →](https://packagist.org/packages/serversideup/spin){rel=""nofollow""} We can use Docker to run `composer` and install it on your project. **Run this command from the parent folder of your project.** ```bash [Install "spin" with Composer] docker run --rm -it -v $(pwd):/app composer require serversideup/spin --dev ``` ## Spin is installed 🥳 You should now be able to access `spin` by running: ```bash [Confirm Spin is working] bash vendor/bin/spin version ``` ### Bonus Tip: Use an alias Rather than typing `vendor/bin/spin` every time, you can add a "smart alias", which will check to see if it exists in your `node_modules`, if not, it loads it from the `vendor` folder. You can add the following below to your `~/.bash_profile` or your `~/.zshrc`. ```bash [Add to your shell profile (recommended)] alias spin='[ -f node_modules/.bin/spin ] && bash node_modules/.bin/spin || bash vendor/bin/spin' ``` You'll now be able to access `spin` from your project root directory. ## Initialize Your Project Once Spin is installed, you can follow the initialization wizard for your project by running `spin init`. ```bash [Initialize Spin with your project] spin init ``` # Install via NPM/Yarn ## Add `spin` to your project with Yarn/NPM Installing `spin` at the project level is a great way to deploy `spin` without much configuration from the user's end. [View `spin` on NPM →](https://www.npmjs.com/package/@serversideup/spin){rel=""nofollow""} We can use Docker to run install `spin` on your project. **Run this command from the parent folder of your project.** ::note The examples below are using `node:latest`. Be sure to change the image name to match your version of Node that you're using for your project. [See available versions →](https://hub.docker.com/_/node/){rel=""nofollow""} :: ```bash [Install "spin" with Yarn + Docker] docker run --rm -v $(pwd):/usr/app/src -w /usr/app/src/ node yarn add @serversideup/spin --dev ``` ```bash [Install "spin" with NPM + Docker] docker run --rm -v $(pwd):/usr/app/src -w /usr/app/src/ node npm install @serversideup/spin --dev ``` ## Spin is installed 🥳 You should now be able to access `spin` by running the command below. ```bash [Run "spin" from your project] ./node_modules/.bin/spin up ``` ### Bonus Tip: Use an alias Rather than typing `./node_modules/.bin/spin` every time, you can add a "smart alias", which will check to see if it exists in your `node_modules`, if not, it loads it from the `vendor` folder. You can add the following below to your `~/.bash_profile` or your `~/.zshrc`. ```bash [Add to your shell profile (recommended)] alias spin='[ -f node_modules/.bin/spin ] && bash node_modules/.bin/spin || bash vendor/bin/spin' ``` You'll now be able to access `spin` from your project root directory. ## Initialize Your Project Once Spin is installed, you can follow the initialization wizard for your project by running `spin init`. ```bash [Initialize Spin with your project] spin init ``` # base64 ## Usage ```bash [Usage for "spin build"] spin base64 [OPTIONS] ``` ### Options - `encode` (or `-e`): Encode a string with base64 - `decode` (or `-d`): Decode a string with base64 ## Examples ```bash [Encode a file with base64] spin base64 -e myfile.txt ``` ```bash [Decode a file with base64] spin base64 decode myfile.txt ``` ## Special notes This command runs the `base64` command on your system, but it standardizes the syntax between Linux and macOS. This means you can use this command on both systems without having to remember the different syntax. # build ## Usage ```bash [Usage for "spin build"] spin build [OPTIONS] ``` ## Official Documentation & Additional Options This command is a shortcut for [`docker-compose build`](https://docs.docker.com/compose/reference/build/){rel=""nofollow""} and can accept additional options that you pass to it. # configure ## Usage ```bash [Usage for "spin configure"] spin configure [options] ``` ## Commands ### GitHub Actions (`gha`) Configure GitHub Actions settings for deploying your application to a specific environment. ```bash [Configure GitHub Actions for an environment] spin configure gha ``` #### What this command does When configuring GitHub Actions, this command: 1. Validates your project setup and GitHub repository connection 2. Creates or uses an existing deployment SSH key 3. Base64 encodes your environment file 4. Sets up required GitHub Actions secrets 5. Configures server access for deployments #### Example ```bash [Configure GitHub Actions for production] spin configure gha production ``` ## Prerequisites Before running `spin configure gha`, ensure you: - Have a GitHub repository set up (`git init` and connected to GitHub) - Are authenticated with GitHub CLI (`spin gh auth login`) - Have an environment file (e.g., `.env.production` for production) - Have your server provisioned with `spin provision` ## Environment Files The command expects an environment file matching your target environment: - Production: `.env.production` - Staging: `.env.staging` - etc. ## GitHub Actions Secrets The following environment variables are set as secrets in GitHub Actions. | Variable | Description | Example Value | Required | | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | -------- | | `_ENV_FILE_BASE64` | The base64 encoded `.env` file. | `ABCDEFG1234...` | ⚠️ Yes | | `_SSH_REMOTE_HOSTNAME` | The hostname/IP of your server. | `server01.example.com` | ⚠️ Yes | | `SSH_DEPLOY_PRIVATE_KEY` | The private SSH key dedicated for the deploy user. | `-----BEGIN OPENSSH PRIVATE KEY-----abc123...` | ⚠️ Yes | | `SSH_REMOTE_KNOWN_HOSTS` | If provided, the SSH connection will validate the connection against your known\_hosts file and remove the "SSH\_KNOWN\_HOST" warning. ([Learn more](https://github.com/serversideup/github-action-docker-swarm-deploy/?tab=readme-ov-file#removing-the-ssh_remote_known_hosts-warning){rel=""nofollow""}) | `github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC...` | no | | `AUTHORIZED_KEYS` | Makes an `authorized_keys` file containing the public keys of "sudo" users that can be used for authenticating other services via SSH (like database GUI connections). | `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC...` | no | To view these environment variables in GitHub Actions, you can follow these steps: 1. Go to your GitHub repository. 2. Click on `Settings`. 3. Click on `Secrets and variables → Actions`.\` ::responsive-image --- maxWidth: 500 alt: Adding a new secret to GitHub Actions src: https://getspin.pro/images/docs/github-actions/gha-secrets.png --- :: ::note The only way you can update a value of a secret is to overwrite the previous value. GitHub Actions does not allow you to view the value of a secret once it's set. If you need to update a value, just run `spin configure gha ` again. :: ## Special Notes - The command will create a new deployment key (under `.infrastructure/conf/ci`) if one doesn't exist - The command will connect to your server and set the newly created deployment key as an authorized key for the docker/deploy user on your server - All secrets are securely stored in your GitHub repository - The command validates your setup before making any changes # debug ## Usage ```bash [Get debug information for "spin"] spin debug ``` # deploy ## Usage ```bash [Usage for "spin deploy"] spin deploy [ -c|--compose-file -p|--port -u|--user ] ``` ## Before getting started Be sure you have "provisioned" your server before running this command. If you haven't, you can do so by running `spin provision` before running `spin deploy`. [Learn how to prepare a server →](https://getspin.pro/docs/server-configuration/server-configuration-basics) ## Example Deployment Command To deploy your application to the production environment, you can use the following command: ```bash [Deploy to Production] spin deploy production ``` To deploy to a staging environment, specify the environment name: ```bash [Deploy to Staging] spin deploy staging ``` You can also provide custom Docker Compose files and SSH options: ```bash [Custom Deployment Options] spin deploy staging --compose-file custom-compose.yml --user myuser --port 2222 ``` This comprehensive process ensures that your application is built, pushed, and deployed efficiently to your server. ## Options The following options are available to set when running this command. | Option | Short | Default | Description | | ---------------- | ----- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | `--compose-file` | `-c` | By default, we look for two files `docker-compose.yml, docker-compose.prod.yml` | The name of the compose files. You can provide many of these options to combine many files. | | `--port` | `-p` | `22` | The port to SSH into the server with. | | `--upgrade` | `-U` | `false` | Force the upgrade of the Ansible collection. | | `--user` | `-u` | The username of your HOST machine (run `whoami` in a new terminal) | The user to SSH into the server with. | ## Change Options with Environment Variables You can also modify the behavior of the `spin deploy` command by setting environment variables: | Environment Variable | Default | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------- | | `SPIN_BUILD_PLATFORM` | `linux/amd64` | The platform to build the Docker image with. | | `SPIN_BUILD_TAGS` | `latest` | The tags to use when building the Docker image. | | `SPIN_INVENTORY_FILE` | `/etc/ansible/collections/ansible_collections/serversideup/spin/plugins/inventory/spin-dynamic-inventory.sh` | The inventory file or dynamic inventory script to use for the deployment. | | `SPIN_PROJECT_NAME` | `spin` | The name of the project to use for the deployment. | | `SPIN_REGISTRY_PORT` | `5080` | The port to use on your local machine for the temporary registry. | | `SPIN_TRAEFIK_CONFIG_FILE` | `./.infrastructure/conf/traefik/prod/traefik.yml` | The Traefik configuration file to use for the deployment. | ## Environment Variables Available For Compose Files The following environment variables are available to use in your compose files after running this command. | Variable | Example | Description | | ------------------------------ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SPIN_IMAGE_*` | `localhost:5080/dockerfile:latest` or `localhost:5080/dockerfile.php:latest` | Automatically generated for each Dockerfile in the project directory. The variable name is derived from the Dockerfile name (e.g., `SPIN_IMAGE_DOCKERFILE` derives from `Dockerfile`, `SPIN_IMAGE_DOCKERFILE_PHP` derives from `Dockerfile.php`), and the value contains the full image name including registry, image name (based on Dockerfile name), and tag. These variables can be used in Docker Compose files to reference the built images. | | `SPIN_MD5_HASH_*` | `abcdef123456` | The MD5 Hash value of all configs under `.infrastructure/conf`. For example, `.infrastructure/conf/traefik/dev/traefik.yml`'s MD5 value will be stored in `SPIN_MD5_HASH_TRAEFIK_YML` | | `SPIN_DEPLOYMENT_ENVIRONMENT` | `production` | The environment you are deploying to. | | Anything from your `.env` file | `DB_PASSWORD` | Any environment variables you have set in your `.env` file. | | `SPIN_APP_DOMAIN` | `example.com` | This variable is created from `APP_URL` and extracts the app domain. This is helpful for frameworks like Laravel when we load up the `.env` file. | ## Using different `.env` files per environment By default, everything runs off the `.env` file. This is great for local development, but it can be a challenge if you want to deploy to multiple environments from the same folder. To solve this, you can create `.env` files for each environment you want to deploy to. For example, you can create `.env.production` and `.env.staging` files. When you run `spin deploy production`, the `.env.production` file will be used. When you run `spin deploy staging`, the `.env.staging` file will be used. ::note This approach is highly reliant on the framework you're using. For example, when you run `spin deploy production`, the `APP_ENV` variable will be set to `production`. [Laravel is intelligent enough](https://laravel.com/docs/12.x/configuration#additional-environment-files){rel=""nofollow""} to know to use the `.env.production` file. If you're using a different framework, you might need to adjust your configuration to use this approach. :: Be sure to add `.env.*` files to your `.gitignore` file so they are not committed to your repository. ## What happens when you run `spin deploy`? Running the `spin deploy` command automates the process of deploying your application to your server. Here's a breakdown of the steps it performs: ### Loads Environment Variables If a `.env` file exists in your project directory, the script loads the environment variables defined in it. ### Sets Default Values The script sets default values for various deployment parameters, which can be overridden by environment variables: - `SPIN_REGISTRY_PORT`: Port for the local Docker registry (default is 5080). - `SPIN_BUILD_PLATFORM`: Platform for building the Docker image (default is "linux/amd64"). - `SPIN_BUILD_IMAGE_PREFIX`: Prefix for the Docker image name (default is "localhost:\"). - `SPIN_BUILD_TAG`: Tag for the Docker image (default is "latest"). - `SPIN_INVENTORY_FILE`: Path to the Ansible inventory file or dynamic inventory script (default is "/etc/ansible/collections/ansible\_collections/serversideup/spin/plugins/inventory/spin-dynamic-inventory.sh"). - `SPIN_SSH_PORT`: SSH port for connecting to the server. - `SPIN_SSH_USER`: SSH user for connecting to the server (default is "deploy"). - `SPIN_PROJECT_NAME`: Name of the project (default is "spin"). ### Checks for Dockerfiles If Dockerfiles are found in the current directory, the script performs the following steps: - Starts a local Docker registry if one is not already running. - Builds a Docker image using `docker buildx`, tagging it with the appropriate name and platform. - Pushes the built Docker image to the local registry. ### Sets Up SSH Tunnel The script establishes an SSH tunnel to the Docker registry on the target server to facilitate secure communication. ### Deploys the Docker Stack The script uses Docker Compose to deploy the Docker stack on the target server, utilizing the specified Docker Compose files. It validates the deployment by checking the exit status of the Docker command. ### Cleans Up The script cleans up by stopping the local Docker registry and terminating the SSH tunnel. # down ## Usage ```bash [Usage for "spin down"] spin down [OPTIONS] ``` ## Special notes This will only run on machines that have `spin` installed on it. This means if you installed `spin` via "composer" or "yarn", this command will **not** execute. # exec ## Usage ```bash [Usage for "spin exec"] spin exec [OPTIONS] SERVICE COMMAND ``` ## Example ```bash [Example of running "php artisan migrate" within the "php" container] spin exec php php artisan migrate ``` The above command runs `php artisan migrate` inside of the `php` service (this is why "php" is repeated twice). ## Special notes This will only run on machines that have `spin` installed on it. This means if you installed `spin` via "composer" or "yarn", this command will **not** execute. # gh ## What this command does This command will run the GitHub CLI via Docker using [`serversideup/github-cli`](https://github.com/serversideup/docker-github-cli){rel=""nofollow""}. ## Usage ```bash [Usage for "spin gh"] spin gh [OPTIONS] ``` ## Official Documentation The `spin gh` command supports running all the commands supported by the GitHub CLI. See the [official documentation](https://cli.github.com/manual/){rel=""nofollow""} for more information. # help ## Usage ```bash [Get help link for Spin] spin help ``` # init ::note This process will create new files and may modify existing files. It's highly recommended you read through our [Add Spin to an Existing Project](https://getspin.pro/docs/getting-started/add-to-an-existing-project) guide before running this command. :: ## Usage ```bash [Usage for "spin init"] spin init [--skip-dependency-install] ``` ## What this command does Running `spin init` will ask you a few questions about your project, then create the files you need to get started with Spin. ### Project Types: - `laravel`: Initialize Spin into an existing Laravel project. - `laravel-pro`: Initialize [Spin Pro's Laravel Template](https://getspin.pro){rel=""nofollow""} into an existing Laravel project with Laravel Pro. - `nuxt`: Initialize Spin into an existing Nuxt project. ### Options - `--skip-dependency-install`: Skip the installation of dependencies. This is useful if you're using a custom script to install dependencies. # kill ## Usage ```bash [Usage for "spin kill"] spin kill ``` # latest ## Usage ```bash [Usage for "spin latest"] spin latest [OPTIONS] SERVICE COMMAND ``` ### Options - `php`: Run the latest stable version of PHP - `node`: Run the latest stable LTS version of Node ## Example ```bash [Example of running a container for "composer install" with PHP] spin latest php php my_script.php ``` The above command will run the latest stable version of `php`, then run the command `php my_script.php` inside the container. The `php` in the command is duplicated because one is the service name name of `php` and the other is the command to run `php` inside the container. # logs ## Usage ```bash [Usage for "spin logs"] spin logs [OPTIONS] ``` ## Official Documentation & Additional Options This command is a shortcut for [`docker-compose logs`](https://docs.docker.com/compose/reference/logs/){rel=""nofollow""} and can accept additional options that you pass to it. # maintain ## Usage ::note When you perform maintenance on your server, your server may experience brief downtime if it the updates require a reboot. Be sure to run this command during a communicated maintenance window. :: ```bash [Usage for "spin maintain"] spin maintain [environment] [ -p|--port -u|--user -U|--upgrade ] ``` ![Spin Maintain Command](https://getspin.pro/images/docs/whats-spin/spin-maintain.png) ## Checklist before executing this command Before you execute this command, you should have the following completed: - You should have a running **Ubuntu 22.04+ server** with properly configured SSH access - The `.spin.yml` file should be configured ## What this command does The above command will: - Connect to your server(s) - Update the all operating system packages - Update Docker - Reboot the server (if needed) ## Options The following options are available to set when running this command. | Option | Short | Default | Description | | ------------- | ----- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------- | | `environment` | - | `all` | Optional. The target environment to maintain (e.g., `production`, `staging`). | | `--host` | `-h` | | The hostname or group of hosts you'd like to apply updates to. | | `--port` | `-p` | `22` | The port to SSH into the server with. | | `--user` | `-u` | The username of your HOST machine (run `whoami` in a new terminal) | The user to SSH into the server with. | | `--upgrade` | `-U` | Check for Ansible collection updates once per day. | Force upgrade the Ansible Collection on your machine before applying updates. | # mkpasswd ## Usage ```bash [Usage for "spin mkpasswd"] spin mkpasswd [OPTIONS] ``` ## Official Documentation & Additional Options This command is a shortcut for running [`mkpasswd`](https://linux.die.net/man/1/mkpasswd){rel=""nofollow""} with Docker. This is helpful for generating temporary password hashes when configuring your `.spin.yml` file. ## Examples ```bash [Generate a password hash] spin mkpasswd mypassword ``` You can also use "interactive mode" by being prompted to enter a password. This is helpful if you don't want to expose the password in your terminal history. ```bash [Generate a password hash interactively] spin mkpasswd ``` # new ## Usage ```txt [Usage for "spin new"] spin new ``` ::note `` can either be an "official template" provided by the Spin team, or any GitHub repository in the format of `username/repo`. :: ## Create a new project with Spin installed Getting started with a new project is easy with Spin. Simply run the `spin new` command followed by your project name and Spin will create a new project for you with Spin installed. ## Official Spin Template running Laravel We only have one official template right now, but we're working to add more templates. This Laravel template that will get you up and running with the latest stable version of Laravel with the default configurations running SQLite. #### Repository - [serversideup/spin-template-laravel-basic](https://github.com/serversideup/spin-template-laravel-basic){rel=""nofollow""} #### Usage ```txt [Usage for "spin new"] spin new laravel ``` ### Optional - Specify your project name By default, Spin will use the framework's default project name and create the project in the current directory of where you're running Spin. If you'd like to specify your own project name, simply add it as the second argument to the `spin new` command. ```bash [Example of "spin new" with custom project name] spin new laravel my-billion-dollar-idea ``` # provision ## Usage ```bash [Usage for "spin provision"] spin provision [environment] [ -p|--port -u|--user -U|--upgrade ] ``` ::note If you're not using our native provider integration, you may need to add `-u root` to the command when you first run it. This will use the `root` user to connect and configure your other users. See our guide on [Using Any Host](https://getspin.pro/docs/providers/use-any-host) for more details. :: ## Checklist before executing this command Before you execute this command, you should have the following completed: - Your [`.spin.yml` file](https://getspin.pro/docs/server-configuration/server-configuration-basics) should be configured - You have at least one provider API token set **OR** you have a server with the `address` property set - If you're using your own server (not through a provider), make sure you have `-u root` set in the command (or whatever your host's default sudo user is) - If you're using a server with the `address` property, make sure you have SSH access to the server and it meets our [server requirements](https://getspin.pro/docs/server-configuration/server-requirements) ## What happens when you run this command? You can learn more [how servers work with Spin](https://getspin.pro/docs/server-configuration/server-configuration-basics#how-servers-work-with-spin) but depending on your set up, below shows what will happen when you run this command: ### If you have a provider API token set - Create your server(s) with your host - Update your `.spin.yml` file with the actual IP address of the server that was just created - Update your server to the latest Linux packages - Configure the provider's firewall to only allow SSH and HTTP/S traffic and apply it to your server - Configure your system users for server access - Harden and secure your server against common attacks - Install and configure Docker Swarm for zero-downtime deployments ### If you have a server with the `address` property set - Connect to your server using SSH - Update your server to the latest Linux packages - Configure your system users for server access - Harden and secure your server against common attacks - Install and configure Docker Swarm for zero-downtime deployments ## Options The following options are available to set when running this command. | Option | Short | Default | Description | | ------------- | ----- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------ | | `environment` | - | `all` | Optional. The target environment to provision (e.g., `production`, `staging`). | | `--host` | `-h` | | The hostname or group of hosts you'd like to provision. | | `--port` | `-p` | `22` | The port to SSH into the server with. | | `--user` | `-u` | The username of your HOST machine (run `whoami` in a new terminal) | The user to SSH into the server with. | | `--upgrade` | `-U` | Check for Ansible collection updates once per day. | Force upgrade the Ansible Collection on your machine before provisioning. | ## Learn More [Configuring your servers for "spin provision" →](https://getspin.pro/docs/server-configuration/server-configuration-basics) # prune ## Usage ```bash [Usage for "spin prune"] spin prune [OPTIONS] ``` ## Options The following options are available to set when running this command. | Option | Short | Default | Description | | --------- | ----- | ------- | ------------------------------------------------------- | | `--force` | `-f` | `false` | Force the deletion of the local Docker and Spin caches. | ## Official Documentation & Additional Options This command is a shortcut for [`docker system prune --all`](https://docs.docker.com/engine/reference/commandline/system_prune/){rel=""nofollow""} and can accept additional options that you pass to it. Spin defaults the `--all` for you already, so no need to add that. If you want to clear volumes as well, you will need to add `--volumes` to the end of the command. ```bash [Clear volumes as well as all other containers.] spin prune --volumes ``` # ps ## Usage ```bash [Usage for "spin ps"] spin ps [OPTIONS] ``` ## Other options You can use any command option from the [docker compose ps](https://docs.docker.com/reference/cli/docker/compose/ps/){rel=""nofollow""} command. # pull ## Usage ```bash [Usage for "spin pull"] spin pull [OPTIONS] ``` ## Official Documentation & Additional Options This command is a shortcut for [`docker-compose pull`](https://docs.docker.com/engine/reference/commandline/compose_pull/){rel=""nofollow""} and can accept additional options that you pass to it. # run ## Usage ```bash [Usage for "spin run"] spin run [OPTIONS] SERVICE COMMAND ``` ## Example ```bash [Example of running a container for "composer install" with PHP] spin run php composer install ``` #### Spin Specific Options - `--skip-pull`: Do not automatically pull docker images. - `--force-pull`: Pull Docker Compose images, regardless of cache settings. ### Official Docker Options This command is a shortcut for [`docker-compose run`](https://docs.docker.com/compose/reference/run/){rel=""nofollow""} and can accept additional options that you pass to it. ## Special notes - This command specifically ignores running container dependencies - It will automatically remove the containers once the command is complete - It adds extra environment variables to improve user-experience if you're running things like "S6 Overlay" inside your containers # stop ## Usage ```bash [Usage for "spin stop"] spin stop ``` # up ## Usage ```bash [Usage for "spin up"] spin up [OPTIONS] ``` ## Example ::note If you're using a Docker Compose configuration with `build:` directives, you might want to get in the habit of using `spin up --build` to ensure you're always running the latest version of your containers. :: ```bash [Force a build of containers on initialization] spin up --build ``` You can add options at the end of the command (like the `--build` shown above. The above command will bring up your containers, but then also force a new build (if you have builds configured in your "docker-compose.dev.yml" file). ## Defaults The `spin up` command defaults to running: ```bash [Command default] COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml docker compose up ``` ## Official Documentation & Additional Options #### Spin Specific Options - `--skip-pull`: Do not automatically pull docker images. - `--force-pull`: Pull Docker Compose images, regardless of cache settings. ### Official Docker Options This command is a shortcut for [`docker compose up`](https://docs.docker.com/compose/reference/up/){rel=""nofollow""} and can accept additional options that you pass to it. It also does a number of other special things. ## Special notes - Make sure to have a `docker-compose.yml` and **by default** a `docker-compose.dev.yml` in your project before running - Spin will automatically pull image updates (only if the machine is connected to the Internet) - Spin will remove any orphan containers ## Overriding the environment with `$SPIN_ENV` Let's say you have a few different files in your repository: ```text [Example project root] . ├── docker-compose.ci.yml ├── docker-compose.production.yml ├── docker-compose.staging.yml ├── docker-compose.testing.yml └── docker-compose.yml ``` By default, Spin uses `docker-compose.yml` and `docker-compose.dev.yml`. If you want to change that, you just need to set `$SPIN_ENV`: ```bash [Change spin environment] SPIN_ENV=testing spin up ``` This will essentially run: ```bash [Above command will execute this below] COMPOSE_FILE=docker-compose.yml:docker-compose.testing.yml docker compose up ``` # update ## Usage ```bash [Usage for "spin update"] spin update ``` ## Special notes This will only run on machines that have `spin` installed to the system. This means if you installed `spin` via "composer" or "yarn", this command will **not** execute. # vault ## Usage ```bash [Usage for "spin vault"] spin vault ``` ## Actions The `spin vault` command will intelligently pass any arguments to your local `ansible-vault` binary or to Docker if Ansible is not installed locally. It will also accept any commands that are documented with [`ansible-vault`](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html){rel=""nofollow""}. ### Most popular actions - `edit`: Edit an encrypted file - `encrypt`: Encrypt an unencrypted file - `decrypt`: Decrypt an encrypted file ## Official Documentation & Additional Options More actions and syntax reference can be found in the [official documentation](https://docs.ansible.com/ansible/latest/cli/ansible-vault.html){rel=""nofollow""}. ## Examples ```bash [Encrypt a file] spin vault encrypt myfile.txt ``` ```bash [Edit an encrypted file] spin vault edit myfile.txt ``` ## Special notes This command will automatically run `ansible vault` via Docker if you do not have Ansible installed on your system. The only major downfall to this approach is when it comes to editing your secret files, you will need to do this all through `vi`, which can be pretty annoying. If you'd like a better experience, you may want to consider installing and configuring Ansible on your local machine so you can edit your secrets with your favorite editor. ## Editing secrets with Sublime Text It's possible to edit your secrets with Sublime Text, but it requires a bit of setup. You'll need to [install Ansible to your system](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html){rel=""nofollow""}. Once Ansible is installed and you're able to execute `ansible-vault` locally, you'll then need to set Sublime Text as your editor. ```bash [Set Sublime Text as your editor] export EDITOR="subl -w" ``` Add this to your `~/.bashrc` or `~/.zshrc` file to make it permanent. ## Saving the file When you save the file with, Ansible Vault will automatically re-encrypt the file for you. You don't need to do anything else. ## Automating Vault Access If you're constantly being asked to provide a vault password, you can speed up your workflow by securely saving your password to a `.vault-password` file in your project root. If that file exists, Ansible will automatically load the password from that file. ::note Never commit `.vault-password` to your repository. It should be added to your `.gitignore` file. :: # version ## Usage ```bash [Usage for "spin version"] spin version ``` # Applying Updates ## How to know an update is available The best way to stay up to date with the latest updates is to subscribe to the releases on GitHub. First, click "Watch" on the Spin Pro repository on GitHub. ::responsive-image --- maxWidth: 500 alt: Watch the Spin Pro repository on GitHub src: https://getspin.pro/images/docs/watch.png --- :: Then we recommend subscribing to releases and security alerts. This way, you'll get an email notification when we release a new version of the Spin Pro template. ::responsive-image --- maxWidth: 500 alt: Subscribe to releases on GitHub src: https://getspin.pro/images/docs/subscribe-to-releases.png --- :: ## How to apply updates Whenever you run `spin new laravel-pro`, you'll automatically use the latest version of Spin Pro. For existing projects, you can use the `spin init laravel-pro` command to delete the previous configurations and provide you with the latest versions. ### If you've made significant changes to the template We understand that some may make changes to the template, so here's the best way to apply updates to customized projects: ::note It may not be a bad idea to have backups of your projects before applying updates, just to be extra safe. :: 1. Subscribe to the releases and review the release notes. 2. Create a new branch on your project. 3. Ensure you're on a clean working branch. 4. Run `spin init laravel-pro` to delete the previous configurations and provide you with the latest versions. 5. Review the changes and make sure everything looks good. 6. Merge the changes into your project. 7. Deploy your changes. # Getting Help ## Community Support We have a private community where you can ask questions, share your projects, and get help from other Spin Pro users. You can access the community by visiting our [private GitHub Discussions](https://github.com/serversideup/spin-template-laravel-pro/discussions){rel=""nofollow""}. ## Resources We offer a number of resources to help you get the most out of Spin Pro: - **[Website](https://getspin.pro/){rel=""nofollow""}** overview of the product. - **[Docs](https://getspin.pro/docs){rel=""nofollow""}** for a deep-dive on how to use the product. - **[Discord](https://serversideup.net/discord){rel=""nofollow""}** for friendly support from the community and the team. - **[Private GitHub Repo](https://github.com/serversideup/spin-template-laravel-pro){rel=""nofollow""}** for source code, bug reports, and project management. - **[Get Professional Help](https://serversideup.net/professional-support){rel=""nofollow""}** - If you need video + screen-sharing support, we offer that too. # License Agreement ## Types of Licenses 1. Personal License: For individual users 2. Team License: For organizations with multiple users ## Personal License The Personal License grants permission to one individual (the "Licensee") to access and use the Templates through a single GitHub account. ## Team License A Team License grants a single organization access for up to 25 individual GitHub accounts for employees within a single legal entity. This license is non-transferable between organizations. ## License Activation, Transfer, and Refunds - Once a license is activated by inviting a GitHub account, it cannot be transferred to another account. - Due to the nature of digital goods, we do not offer refunds for purchased licenses. All sales are final. ## Permitted Uses You are permitted to: - Use the Templates to create unlimited end products. - Modify the Templates to create derivative works for your own projects, including commercial works. - Use the Templates in open-source projects, provided you do not resell the Templates or derivatives. ## Restrictions You are not permitted to: - Use the Templates to create products that allow end users to build their own end products using the Templates or derivatives. - Redistribute the Templates or derivatives separately from an end product. - Share your access to the Template repository with any other individual outside of your licensed accounts. - Use the Templates to produce anything deemed by 521 Dimensions LLC (DBA Server Side Up) to be competitive or in conflict with their business. - Sell or redistribute the original or modified Templates in any form, including incorporating them into a GUI or other platform for resale. ## Distribution - Each user must have their own GitHub account. Sharing access or redistributing the Templates through other channels is prohibited. - The Templates can be used to sell self-hosted applications, provided the focus is on the application, not the Templates themselves. ## Support and Updates - Community-based support is available through our private GitHub Discussions forum, which you can access with your license. - This forum allows users to ask questions, share knowledge, and discuss best practices. - While we strive to maintain an active and helpful community, please note: - Responses are provided on a best-effort basis by community members and our team. - We do not offer guaranteed response times or Service Level Agreements (SLAs). - One-on-one support, including screen sharing or direct troubleshooting of your specific setup, is not included. - For bug reports or feature requests, please open an issue on our GitHub repository [here](https://github.com/serversideup/spin-template-laravel-pro/issues){rel=""nofollow""}. - We regularly update the Templates. Your license includes lifetime access to these updates at no additional cost. This means you will have access to all future versions and improvements of the Templates for as long as we continue to offer them, without having to repurchase or renew your license. We encourage users to actively participate in the community, both in seeking and providing help. This collaborative environment benefits everyone and helps improve the overall quality of the Templates. ## Example Usage Examples of usage **allowed** by the license: - Creating a personal or commercial application for yourself or a client using the Templates. - Modifying the Templates to suit the specific needs of a project you are working on. - Using the Templates as part of a self-hosted application that is sold to end users for a one-time fee, where the value of the sale is found in the application (not the templates). - Integrating the Templates into an open-source project where the primary purpose is clearly not to simply re-distribute the Templates, and the source code is publicly available. Examples of usage **not allowed** by the license: - Creating a repository of your favorite Docker templates or derivatives based on the Templates and publishing it publicly. - Creating a library of Docker templates using the Templates and making it available either for sale or for free. - Converting the Templates to another framework and making it available either for sale or for free. - Creating a platform or service that allows end users to generate their own Docker files using the Templates or derivatives. - Creating a GUI or web service that allows users to generate Docker files using the Templates or derivatives. - Creating a theme, template, or starter kit using the Templates and making it available either for sale or for free. - Creating a tool similar to Spin and offering it for sale or for free. - Creating any end product that is not the sole property of either yourself or a client of yours. For example, your employees or contractors can't use your company license to build their own projects. - Giving someone access to the Templates when they purchase a product or service from you. For example, you can't use a Personal License as a way to give someone access to the Templates when they purchase an online course from you. - Selling access to your account or the Templates. ## Contributions We welcome and appreciate contributions from our community. By submitting a contribution (e.g. code, documentation, ideas) to this project, you agree to the following: 1. Your contribution will be licensed under the same terms as this project. 2. You grant 521 Dimensions LLC (DBA Server Side Up) a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, modify, and distribute your contribution as part of this project. 3. You certify that you have the right to grant this license for your contribution. We value all contributions and will give appropriate credit where possible. However, please note that contributing does not grant you any ownership rights in the project as a whole. Thank you for helping improve our project! ## Enforcement If you are found to be in violation of the license, access to your Server Side Up account will be terminated, and a refund may be issued at our discretion. When license violation is blatant and malicious (such as intentionally redistributing the Components or Templates through private warez channels), no refund will be issued. The copyright of the Components and Templates is owned by 521 Dimensions LLC. You are granted only the permissions described in this license; all other rights are reserved. 521 Dimensions LLC reserves the right to pursue legal remedies for any unauthorized use of the Components or Templates outside the scope of this license. ## Termination 521 Dimensions LLC (DBA Server Side Up) reserves the right to terminate this license agreement at any time if you are found to be in violation of any terms outlined in this agreement. Upon termination, you must immediately cease all use of the Templates and destroy any copies in your possession. ## Limitation of Liability TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL 521 DIMENSIONS LLC (DBA SERVER SIDE UP) BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THE TEMPLATES, EVEN IF 521 DIMENSIONS LLC HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY CASE, 521 DIMENSIONS LLC'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS LICENSE AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR THE LICENSE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, SO THE ABOVE LIMITATION MAY NOT APPLY TO YOU. YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE TEMPLATES IS AT YOUR SOLE RISK AND THAT THE TEMPLATES ARE PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM 521 DIMENSIONS LLC. ## Warranties and Disclaimer THE TEMPLATES ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 521 DIMENSIONS LLC (DBA SERVER SIDE UP) MAKES NO WARRANTIES OR REPRESENTATIONS REGARDING THE USE OF THE TEMPLATES IN TERMS OF THEIR CORRECTNESS, ACCURACY, RELIABILITY, OR OTHERWISE. ## Governing Law and Jurisdiction This Agreement is governed by the laws of the State of Wisconsin, USA. Any legal proceedings related to this Agreement may only be brought in the courts of Wisconsin, and you hereby consent to the exclusive jurisdiction of such courts. You agree to service of process at the e-mail address on your original order. ## Price Adjustments We reserve the right to adjust the pricing of our licenses in the future. Any price changes will not affect already purchased licenses but may apply to future purchases. ## Questions? Unsure if your use case is covered by our license? We're here to help! Please don't hesitate to reach out to us at with any questions you may have. We're always happy to clarify and assist you in understanding how our license applies to your specific situation. Last Updated: August, 20th 2024 # Terms and Conditions ## 1. Introduction By using the 521 Dimensions LLC (DBA Server Side Up) website and services, you confirm your acceptance of, and agree to be bound by, these Terms and Conditions. ## 2. Definitions "We", "Us", "Our", or "Server Side Up" refers to 521 Dimensions LLC (DBA Server Side Up). "You" or "User" refers to the person or entity using our website or services. "Website" refers to {rel=""nofollow""} and {rel=""nofollow""}. "Services" refers to any products, services, or content offered by Server Side Up. ## 3. Use of Website and Services 3.1. You agree to use our website and services only for lawful purposes and in a way that does not infringe the rights of, restrict, or inhibit anyone else's use and enjoyment of the website. 3.2. We reserve the right to modify, suspend, or discontinue any part of our services at any time without notice or liability. ## 4. Intellectual Property 4.1. All content on our website, including but not limited to text, graphics, logos, images, and software, is the property of Server Side Up or its content suppliers and is protected by United States and international copyright laws. 4.2. You may not reproduce, distribute, modify, or create derivative works of any material from our website without our express written permission. ## 5. User-Generated Content 5.1. By submitting any content to our website or services, you grant us a worldwide, non-exclusive, royalty-free license to use, reproduce, modify, adapt, publish, translate, and distribute it. 5.2. You are solely responsible for any content you submit, and we are not responsible for the content or accuracy of any user-generated content. ## 6. Privacy Policy Your use of our website and services is also governed by our Privacy Policy, which is incorporated into these Terms and Conditions by reference. ## 7. Limitation of Liability To the fullest extent permitted by applicable law, Server Side Up shall not be liable for any indirect, incidental, special, consequential, or punitive damages, or any loss of profits or revenues, whether incurred directly or indirectly, or any loss of data, use, goodwill, or other intangible losses resulting from: (a) your use or inability to use our services; (b) any unauthorized access to or use of our servers and/or any personal information stored therein; (c) any interruption or cessation of transmission to or from our services; (d) any bugs, viruses, trojan horses, or the like that may be transmitted to or through our services by any third party. ## 8. Indemnification You agree to indemnify and hold harmless Server Side Up, its affiliates, officers, directors, employees, and agents, from and against any claims, liabilities, damages, losses, and expenses, including, without limitation, reasonable legal and accounting fees, arising out of or in any way connected with your access to or use of our services or your violation of these Terms and Conditions. ## 9. Changes to Terms and Conditions We reserve the right to modify these Terms and Conditions at any time. We will provide notice of any material changes by posting the new Terms and Conditions on our website. Your continued use of our services after any such changes constitutes your acceptance of the new Terms and Conditions. ## 10. Contact Information If you have any questions about these Terms and Conditions, please contact us at . Last Updated: August 20th, 2024 # How Spin Works ## Spin stays out of your way Spin is designed to be flexible and gives you the power to choose what you'd like Spin to help you with. For example, if you want to use your current PaaS provider for production deployments, but you just want to use Spin for local development, you can easily do that without Spin getting in the way. Simply delete the `docker-compose.prod.yml` file and you won't need to do anything else. ## What Spin Is Built On Top Of ![Spin Diagram](https://getspin.pro/images/docs/whats-spin/spin-diagram.png) At the core of Spin are: - [Docker Compose](https://docs.docker.com/compose/){rel=""nofollow""} (used in local development) - [Docker Swarm Mode](https://docs.docker.com/engine/swarm/){rel=""nofollow""} (used in production, staging, etc.) - [Ansible](https://www.ansible.com/){rel=""nofollow""} (used to ensure your server is configured correctly) ### Templates Spin uses templates to quickly scaffold new projects with Docker Compose configurations for local development and production deployments. ### Flexible deployments With Spin, you have two options for deployments: 1. **GitHub Actions** - We have open source workflows that follow the Spin structure to help you build and deploy your application with ease. 2. [**`spin deploy`**](https://getspin.pro/docs/command-reference/deploy) - For smaller teams and very simple deployments, `spin deploy` will deploy your application without any downtime or the headaches of managing a CI/CD pipeline. ### Other open source projects we use Spin accesses and utilizes other open source projects to simplify your development lifecycle experience. The entire system is built on top of open source libraries, but here are a few notable ones to be aware of: #### Ansible Collection - [Spin Ansible Collection](https://github.com/serversideup/ansible-collection-spin){rel=""nofollow""} - Used to provision and maintain your production server. #### GitHub Actions - [serversideup/docker-build-action](https://github.com/marketplace/actions/docker-build-action){rel=""nofollow""} - A simplified syntax to build and publish your Docker images with GitHub Actions. - [serversideup/docker-swarm-deploy-github-action](https://github.com/marketplace/actions/docker-swarm-deploy-github-action){rel=""nofollow""} - A simplified syntax to deploy to Docker Swarm Mode via GitHub Actions. #### Docker Images - [serversideup/php](https://serversideup.net/open-source/docker-php/){rel=""nofollow""} - PHP Docker images highly optimized to work with Laravel + Spin. - [serversideup/docker-ssh](https://github.com/serversideup/docker-ssh){rel=""nofollow""} - A lightweight docker image that runs SSH. This is a fantastic method on using a secure SSH tunnel into your database cluster. - [serversideup/docker-ansible](https://github.com/serversideup/docker-ansible){rel=""nofollow""} - A lightweight docker image that runs Ansible. This allows users to provision their server without needing to know how to install or maintain their Ansible installation. - [serversideup/docker-github-cli](https://github.com/serversideup/docker-github-cli){rel=""nofollow""} - A lightweight docker image that runs GitHub CLI. This allows users to interact with GitHub without needing to install the GitHub CLI on their machine. ## Why not just use these technologies directly? Spin is designed to reduce the learning curve for delivering containerized applications with Docker. This is where we believe the 99% of people are. If you're looking to start a new project and deliver it quickly without breaking the bank, Spin is for you. Everything is designed to have your application disposable, repeatable, and scalable. For some advanced users that are running massive server farms, you might want to stick to your existing tooling. Spin is focused on launching apps from the ground up with the ability to scale. In large clusters, you might need to write your own tooling to match your existing use case. The good news is **you don't need to use Spin everywhere.** Spin is a *structure* just as much as it is a tool. Spin is designed to be there when you need it and get out of your way when you don't. ## Important concepts Spin's flexibility comes from embracing the [Docker Compose Overrides (aka Docker Compose Extends)](https://docs.docker.com/compose/multiple-compose-files/extends/){rel=""nofollow""} structure. We use a "base" `docker-compose.yml` file, then choose a file based on the environment. Here is a visual of what the file structure looks like: ![Docker Compose Overrides](https://getspin.pro/images/docs/whats-spin/docker-compose-overrides.png) Docker natively selecting these files, but it is a huge pain to type out each time. This is what we would have to type to bring our project up. ```bash [What we would have to type with Docker Compose 😅] docker compose pull && docker compose -f docker-compose.yml -f docker-compose.dev.yml up ``` Here's how this command compares in Spin: ```bash [What we type with Spin 🥳] spin up ``` ### Further example To see this from a code perspective, let's take a look at this: ![Docker Compose Overrides Code](https://getspin.pro/images/docs/whats-spin/docker-overrides-code.png) ```yaml [If we were to run "spin up", our expected result of Docker Compose that we'll run] services: php: image: serversideup/php:8.3-fpm-nginx environment: PRODUCTION: "false" node: image: node:lts ``` You can see the files are merged intelligently so you can manage infrastructure like an "object" in programming. ## Spin Syntax You'll notice Spin follows the same syntax as the tool it's built on top of. For example, `spin up` runs `docker compose up` and supports any CLI option that `docker compose up` supports. This is intentional by design because we really hate it when tools introduce their own domain specific language on top of other tools. Spin is here to make your process easy and centralized. We follow the design of the other tools we built from so it's easy for you to find developers that are familiar with the technology, find support online, and scale easily from Spin on. ## Framework Agnostic One other thing that we spent a lot of time on is writing everything so Spin is framework agnostic. Containerizing applications gives you incredible power to deliver your application anywhere like never before. We'd be fools if we built Spin to work with just one framework only. The power of Docker enables us to give you quality development environments to all developers (regardless if they are running Mac, Windows, or Linux). You'll notice Spin is written in vanilla Bash. Yup... you read that correctly. Many people think we're crazy for doing this and they've suggested "X", "Y", and "Z" would have been a better programming language, but the biggest reason why we did this was so we could deliver an experience with **no additional development dependency**. We intentionally chose to support Bash V3 so MacOS users can just download it and run it. There's no need for the user to figure out how to install Ruby, upgrade Bash, etc. It just works out of the box. # Create a new project ```bash [Create a new Laravel project called "my-billion-dollar-idea"] spin new laravel-pro my-billion-dollar-idea ``` You'll have a few prompts to complete during the project creation process. Follow the on-screen instructions to complete the process. :video{autoPlay="true" loop="true" muted="true" playsInline="true"} ## Bring up your development environment Now that we have our project created, we can bring up our development environment. [Learn how to bring up your development environment →](https://getspin.pro/docs/development-environment/starting-up-your-development-environment) # Add to an existing project ```bash [Run "spin init"] spin init laravel-pro ``` ## Important notes 1. Make sure you have backups of your local database and any other important data. 2. Run this on a test branch and test thoroughly. 3. `spin init` will remove configurations and replace them with Spin Pro configurations. 4. We will also attempt to automatically update your `.env`. and `.env.example` files. 5. Projects with dumped migration schemas (with `schema:dump`) should skip Laravel Auto-migrations and will need to [install the SQL client manually](https://getspin.pro/docs/services/laravel-schema-dump). ## Follow the instructions Follow the instructions in the terminal. It'll take you through the process of adding Spin Pro to your project. :video{autoPlay="true" loop="true" muted="true" playsInline="true"} ## Bring up your development environment Now that we have our project created, we can bring up our development environment. [Learn how to bring up your development environment →](https://getspin.pro/docs/development-environment/starting-up-your-development-environment) # Starting Up Your Development Environment :video{autoPlay="true" loop="true" muted="true" playsInline="true"} ## Prerequisites - ✅ Docker must be installed and running - ✅ Spin must be installed ## Configure local, trusted SSL for development If you want your development URLs to have a trusted SSL certificate, you'll need to install the Server Side Up Certificate Authority on your machine. This certificate authority is only used for development URLs like `*.dev.test`. In production, we use Let's Encrypt from Traefik to generate our certificates. No configuration is necessary to trust a Let's Encrypt certificate. You can also use your own certificates if you prefer. We use [cfssl](https://github.com/cloudflare/cfssl){rel=""nofollow""} to generate our certificates, but as long as the certificates are valid and trusted by your machine, you can use them. [Learn how to install and trust the Server Side Up Certificate Authority →](https://serversideup.net/ca){rel=""nofollow""} ## Configure your hosts file In order to access your development URLs, you will need to create a "hosts" entry to point back to your local machine for each development URL. When you're developing locally, you'll be able to use domain names like `laravel.dev.test` instead of `localhost`. This is important because it allows you to mimic a real-world environment where each project has its own domain name. This is especially important if you're working on multiple projects at the same time. We have an [open discussion on GitHub](https://github.com/serversideup/spin/discussions/51){rel=""nofollow""} to automate this functionality, but for now this is the best and easiest solution. We also have instructions to [customize your development URLs](https://getspin.pro/docs/advanced/customizing-development-urls) if you want to use a different domain name. [Learn how to configure your hosts file →](https://getspin.pro/docs/advanced/configuring-your-hosts-file) ## Bring up your development environment Once we have these one-time steps completed, we can now bring up your development environment. ::note Make sure to run this command from your project directory. :: ```bash [Bring up your development environment] spin up ``` ::note To stop your development environment, press `Ctrl+C`. :: Since Spin is running Docker Compose, you can also pass any argument to the `up` command. For example, `spin up -d` will start your development environment in detached mode. See the full documentation for [spin up](https://getspin.pro/docs/command-reference/up) for more information. ## Bringing up Node services By default, our project is configured to use `yarn`. If you want to utilize hot module reloading with Vite, run the following command in a **new terminal**. ```bash [Start Vite] spin run node yarn dev ``` ## Accessing your development URLs When the services are up and running, you can access the following URLs: - **Web Server**: {rel=""nofollow""} - **Mailpit**: {rel=""nofollow""} - **Vite**: {rel=""nofollow""} - **Reverb**: - **Meilisearch**: {rel=""nofollow""} ## Connecting to your database If you want to connect a database client to your database, you can follow our guide on connecting to your database. [Learn how to connect to your database →](https://getspin.pro/docs/advanced/connecting-to-your-database) ## Running commands in development You can run commands in your development environment using the `spin run` or the `spin exec` command. We created a guide to help you understand the difference between the two. [Learn how to run commands in development →](https://getspin.pro/docs/development-environment/running-commands-in-development) # Running Commands in Development ## How to run commands in development You have two options to run commands in your development environment: 1. [`spin exec`](https://getspin.pro/docs/command-reference/exec) - This executes commands in an EXISTING container (and requires that service to be already running with `spin up`). 2. [`spin run`](https://getspin.pro/docs/command-reference/run) - This executes commands in a NEW container, then exits. For example, let's say you want to run `composer install` in your development environment for Laravel, you would use the following command: ::note If you have `spin up` running in a terminal window, you will need to run the `spin run` or `spin exec` command in a new terminal window from your project directory. :: ```bash [Run a command in a new container] # Usage: spin run spin run php composer install ``` ```bash [Execute a command in an existing container] # Usage: spin exec spin exec php composer install ``` Take note of the syntax. You specify the service you want to run the command in, then the command you want to run. The same is true for `spin exec`. ## When to use `spin exec` vs `spin run` In development, it's often easier to use `spin run` because it will create a new container and then exit. This is faster than having to start the container with `spin up` and then use `spin exec`. If you have something that you specifically need to run in an already running container, then you should use `spin exec`. # Server Requirements ## Choose a host We've run [VPS Benchmarks against a number of hosts](https://521dimensions.notion.site/VPS-Benchmarks-for-Self-hosters-c6eca7c5f16d4bb8aeb989174fc58ffe?pvs=4){rel=""nofollow""} and have found the following hosts to have great value. The links below are referral links, meaning we get a small kickback if you sign up -- but this doesn't affect our recommendations. ### Hetzner Hetzner is a German-based company with data centers in the EU and the US. Their pricing is very competitive and they have incredible performance. With the link below, they offer €⁠20 (\~$21 USD) credits free which can get you a server for a few months. [Sign Up with Hetzner →](https://hetzner.cloud/?ref=lhLUIrkdUPhl){rel=""nofollow""} ### Vultr Vultr is a US-based company that has a great reputation for performance and value. They have a wide range of data centers around the world and a great API for automation. With the link below, they are offering $100 in credits -- which can get you quite a bit for a few months. [Sign Up with Vultr →](https://www.vultr.com/?ref=9627777-8H){rel=""nofollow""} ### Digital Ocean Digital Ocean is a US-based company that has data centers all around the world. Although their performance generally lacks compared to other providers, there are so many resources that natively support their offerings. With the link below, they are offering $200 in credits over 60 days. [Sign Up with Digital Ocean →](https://m.do.co/c/f3bad4b927ca){rel=""nofollow""} ### Any other host Spin is host-agnostic, meaning you can run Spin anywhere. If you have a preferred host, you can use them as well. Just make sure that your host meets the following requirements below. ## Recommended Server Specs ::note Note if you use any of our supported providers in the left sidebar, we'll automatically configure everything for you. 🤓 :: Hardware specs largely depend on your project, but even for simple apps, we recommend the following: - **CPU**: 1 CPU core - **RAM**: 1GB - **Storage**: >25GB SSD - **Architecture**: x86\_64 (64-bit) \[[request ARM64 support](https://github.com/serversideup/spin/discussions/9){rel=""nofollow""}] - **Operating System**: Ubuntu 22.04 LTS or newer ([**must be an LTS version**](https://ubuntu.com/about/release-cycle){rel=""nofollow""}) - **Snapshots/Backups**: Highly recommended - **Firewall**: Configured to allow SSH and HTTPS traffic (22/tcp, 80/tcp, 443/tcp, 2222/tcp) - **Access**: Root SSH access is required **Spin requires a fresh server installation.** Do not install Spin on servers that already have control panels (like Plesk, cPanel) or other server management tools (like Laravel Forge) installed, as this can cause configuration conflicts. ## Next steps The next step is to understand how servers work with Spin. [Learn how servers work with Spin →](https://getspin.pro/docs/server-configuration/server-configuration-basics) # Server Configuration Basics ## 👉 Important: Spin doesn't need to manage your servers if you don't want it to It's kind of weird to start a document to talk about how NOT to use a feature, but we want to show the flexibility that Spin gives you. If you're satisfied with your current hosting provider, you don't need to use Spin to manage your servers. You can easily configure your PaaS to use the same Dockerfiles that you're using in development with Spin. You'll just need to reference your PaaS's own documentation on how to do this. All you need to do is delete the `.spin.yml` and any `docker-compose.*.yml` files that you don't want and `spin up` will still work perfectly fine. If you prefer to not have any vendor lock-in from a PaaS provider and you're interested in the full control of your own servers, keep reading! Spin will give you the power of a PaaS without the restriction of running your application on a specific platform. ## How servers work with Spin Spin places all of its configuration in the `.spin.yml` file. This file is used to configure your servers, users, connections to providers, and more. When you run `spin provision`, Spin will pull down [our Ansible Docker image](https://github.com/serversideup/docker-ansible/){rel=""nofollow""} and use the [Spin Ansible Collection](https://github.com/serversideup/ansible-collection-spin){rel=""nofollow""} to configure your providers and servers. ![Spin Provision Diagram](https://getspin.pro/images/docs/whats-spin/spin-provision.png) ## Connect a provider or bring your own server You can see our ever expanding list of providers on the left sidebar. If you'd like to use a provider that isn't listed, you can easily [use your own server](https://getspin.pro/docs/providers/use-any-host). This means you can run Spin on any host that meets the [Spin Server Requirements](https://getspin.pro/docs/server-configuration/server-requirements), including big cloud providers down to an old computer running in your grandmother's basement 🤠. If you connect a provider via an API token, you'll get added benefits of automated server creation, backups, firewalls, and more. ## The `.spin.yml` file The main configuration file for using servers with Spin is the `.spin.yml` file. Whenever you run `spin new` or `spin init`, this file is created. By default, the `.spin.yml` file is not included in your Git repository. You could think of it as an `.env` file for your servers. The file can contain sensitive information, so be sure to keep it secure. [Learn how to use the .spin.yml file →](https://getspin.pro/docs/server-configuration/spin-yml-usage) ## Provision your server on any host Once you have your `.spin.yml` file configured, we can use `spin provision` to provision your server on any host that meets the [Spin Server Requirements](https://getspin.pro/docs/server-configuration/server-requirements). Pick the provider you'd like to use to learn more: - [Hetzner](https://getspin.pro/docs/providers/hetzner) - [Vultr](https://getspin.pro/docs/providers/vultr) - [Digital Ocean](https://getspin.pro/docs/providers/digitalocean) - [Any other host](https://getspin.pro/docs/providers/use-any-host) # .spin.yml Usage ## Example `.spin.yml` file Here's an example of what the `.spin.yml` file looks like: ```yaml [.spin.yml] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: - username: alice name: Alice Smith groups: ['sudo'] authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" - username: bob name: Bob Smith state: present password: "$6$mysecretsalt$qJbapG68nyRab3gxvKWPUcs2g3t0oMHSHMnSKecYNpSi3CuZm.GbBqXO8BE6EI6P1JUefhA0qvD7b5LSh./PU1" groups: ['sudo'] shell: "/bin/bash" authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1anotherfakekeyIMVIzwQXBzxxD9b8Erd1FKVvu bob" ############################################################## # 👇 Providers - You must set at least one provider ############################################################## providers: - name: digitalocean api_token: Set token here OR delete this line and set environment variable DO_API_TOKEN - name: hetzner api_token: Set token here OR delete this line and set environment variable HCLOUD_TOKEN - name: vultr api_token: Set token here OR delete this line and set environment variable VULTR_API_KEY ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: - server_name: ubuntu-2gb-ash-1 environment: production hardware_profile: hetzner_2c_2gb_ubuntu2404 - server_name: ubuntu-1gb-ord-2 environment: staging hardware_profile: vultr_1c_1gb_ubuntu2404 ############################################################## # 🤖 Hardware Profiles ############################################################## hardware_profiles: # Hetzner - name: hetzner_2c_2gb_ubuntu2404 provider: hetzner profile_config: location: ash server_type: cpx11 image: ubuntu-24.04 backups: true # Vultr - name: vultr_1c_1gb_ubuntu2404 provider: vultr profile_config: region: ord plan: vc2-1c-1gb os: "Ubuntu 24.04 LTS x64" backups: true # DigitalOcean - name: digitalocean_1c_1gb_ubuntu2404 provider: digitalocean profile_config: region: nyc3 size: s-1vcpu-1gb image: ubuntu-24-04-x64 backups: true ############################################################## # 🌎 Environments ############################################################## environments: - name: production - name: staging - name: development ############################################################## # 🤓 Advanced Server Configuration ############################################################## # Timezone and contact settings server_timezone: "Etc/UTC" server_contact: admin@example.com # If you the SSH port below, you may need to run `spin provision -p ` # to get a connection on your first provision. Otherwise, SSH will try connecting # to your new port before the SSH server configuration is updated. ssh_port: "22" ## You can set this to false to require a password for sudo. ## If you disable passwordless sudo, you must set a password for all sudo users. ## generate an encrypted hash with `spin mkpasswd`. Learn more: ## https://serversideup.net/open-source/spin/docs/command-reference/mkpasswd use_passwordless_sudo: true ## Email Notifications postfix_hostname: "{{ inventory_hostname }}" ## Set variables below to enable external SMTP relay # postfix_relayhost: "smtp.example.com" # postfix_relayhost_port: "587" # postfix_relayhost_username: "myusername" # postfix_relayhost_password: "mysupersecretpassword" ## Deploy user customization - You can customize the deploy user below if you'd like # docker_user: # username: deploy # authorized_ssh_keys: # - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKNJGtd7a4DBHsQi7HGrC5xz0eAEFHZ3Ogh3FEFI2345 fake@key" # - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFRfXxUZ8q9vHRcQZ6tLb0KwGHu8xjQHfYopZKLmnopQ anotherfake@key" ``` ## Users You'll need to configure a user for your server. This will be the user that you use to SSH into your server. ::note For your best user experience, you might want to consider having the `username` match the username on your host machine. You can run `whoami` to see your current username and use that as the `username` in your `.spin.yml` file. :: ```yaml [.spin.yml Server Users] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: - username: alice name: Alice Smith groups: ['sudo'] authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" - username: bob name: Bob Smith state: present password: "$6$mysecretsalt$qJbapG68nyRab3gxvKWPUcs2g3t0oMHSHMnSKecYNpSi3CuZm.GbBqXO8BE6EI6P1JUefhA0qvD7b5LSh./PU1" groups: ['sudo'] shell: "/bin/bash" authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1anotherfakekeyIMVIzwQXBzxxD9b8Erd1FKVvu bob" ``` The above configuration is creating two users: `alice` and `bob`. Both users are added to the `sudo` group, which allows them to use `sudo` to run commands with elevated privileges (such as `sudo su` to get a root shell). | Variable | Description | Example | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | | `username` | The username of the user. | `alice` | | `name` | The full name of the user. | `Alice Smith` | | `groups` | The groups the user belongs to. Default `sudo` group gives the user root capabilities. Separate multiple groups with a comma. | `['sudo', 'docker']` | | `authorized_keys.public_key` | The authorized public SSH key that can connect to the server for this user. | `ssh-ed25519 AAA...d1FKVvu alice` | | `password` | The encrypted password for the user. Generate an encrypted hash with [`spin mkpasswd`](https://getspin.pro/docs/command-reference/mkpasswd). The user will be prompted to change their password on first login. The password will only be used if `use_passwordless_sudo` is set to `false`. | `$6$mysecretsalt$...` | ### Setting your SSH public key To get your SSH public key, look for files under your `~/.ssh` folder. The filename could be something like `id_ed25519.pub` or `id_rsa.pub`. Just make sure the file ends with `.pub`. Once you find the file, you can get the contents of the public key by running this command: ```bash [Get SSH public key] # Change the filename if your key is named differently cat ~/.ssh/id_ed25519.pub ``` You should see something that looks like this: ```text [Example SSH public key] ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your_email@example.com ``` Copy the entire line (including the "ssh-ed25519" part) and paste it into your `.spin.yml` file as shown in the example above. ### Generating a new SSH key If you need to generate a new SSH key, see our guide on [generating a secure SSH key](https://getspin.pro/docs/advanced/generating-a-secure-ssh-key). ## Providers ::note Providers are only required if you want Spin to automatically create servers. If you're using existing servers, see our guide on [using your own servers with Spin](https://getspin.pro/docs/providers/use-any-host). :: The `providers:` section in your `.spin.yml` configures connections to supported cloud providers. Spin natively supports these providers: | Provider | Configuration Name | Environment Variable | | --------------------------------------------------------------- | ------------------ | -------------------- | | [DigitalOcean](https://getspin.pro/docs/providers/digitalocean) | `digitalocean` | `DO_API_TOKEN` | | [Hetzner](https://getspin.pro/docs/providers/hetzner) | `hetzner` | `HCLOUD_TOKEN` | | [Vultr](https://getspin.pro/docs/providers/vultr) | `vultr` | `VULTR_API_KEY` | ::note API tokens grant powerful access to your cloud resources. For better security, you may consider storing your API tokens as environment variables on your local machine (using `.env` files or your preferred secure method) instead of directly in `.spin.yml`. :: Click on any provider name above for detailed configuration instructions. ## Hardware Profiles The `hardware_profiles:` section defines the server resources and provider for each server. Each hardware profile references a provider and specifies the server's resources. Each hardware profile structure is slightly different depending on the provider. Click on a provider name above for detailed configuration instructions. ## Servers The `servers:` section defines the servers that Spin will create and manage. Each server requires a few key properties to determine its configuration. Here's an example of configuring two servers: ```yaml [.spin.yml] servers: - server_name: ubuntu-2gb-ash-1 environment: production hardware_profile: hetzner_2c_2gb_ubuntu2404 - server_name: ubuntu-1gb-ord-2 environment: staging hardware_profile: vultr_1c_1gb_ubuntu2404 ``` | Property | Description | Example | Required | | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | -------------------------------------- | | `server_name` | A unique, descriptive name for your server. Use alphanumeric characters and hyphens only (no spaces or special characters). | `web-server-1` | Yes | | `environment` | The deployment environment (`production`, `staging`, `development`). Must match an environment defined in your `.spin.yml` file. | `production` | Yes | | `hardware_profile` | References a hardware profile defined in your `.spin.yml` that specifies the server's resources and provider. | `hetzner_2c_2gb_ubuntu2404` | Only if you intend to use a provider | | `address` | The server's IP address or hostname. Leave blank for auto-assigned IPs - Spin will update this after provisioning. :br:br**Using existing servers?** ⚠️ You must specify the IP address or hostname here. | `1.2.3.4` | Only if you are using existing servers | ## Environments Environments are managed under the `environments:` section in your `.spin.yml` file. You can define as many environments as you'd like or change the names of the environments. The most important thing to remember is the `environment` property in the `servers:` section must match an environment defined in your `.spin.yml` file. You can also set the `backups` property to `true` or `false` to enable or disable backups for the environment. If the `backups` property is set on a server, it will override the environment setting. ```yaml [Example environments configuration in .spin.yml] ############################################################## # 🌎 Environments ############################################################## environments: - name: production - name: staging - name: development backups: false ``` ## Advanced Server Configuration We also give you a few other options to configure your servers that will configure the behavior for the [Spin Ansible Collection](https://github.com/serversideup/ansible-collection-spin){rel=""nofollow""}. ```yaml [.spin.yml Advanced Server Configuration] ############################################################## # 🤓 Advanced Server Configuration ############################################################## # Timezone and contact settings server_timezone: "Etc/UTC" server_contact: admin@example.com # If you the SSH port below, you may need to run `spin provision -p ` # to get a connection on your first provision. Otherwise, SSH will try connecting # to your new port before the SSH server configuration is updated. ssh_port: "22" ## You can set this to false to require a password for sudo. ## If you disable passwordless sudo, you must set a password for all sudo users. ## generate an encrypted hash with `spin mkpasswd`. Learn more: ## https://serversideup.net/open-source/spin/docs/command-reference/mkpasswd use_passwordless_sudo: true ## Email Notifications postfix_hostname: "{{ inventory_hostname }}" ## Set variables below to enable external SMTP relay # postfix_relayhost: "smtp.example.com" # postfix_relayhost_port: "587" # postfix_relayhost_username: "myusername" # postfix_relayhost_password: "mysupersecretpassword" ## Deploy user customization - You can customize the deploy user below if you'd like # docker_user: # username: deploy # authorized_ssh_keys: # - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKNJGtd7a4DBHsQi7HGrC5xz0eAEFHZ3Ogh3FEFI2345 fake@key" # - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFRfXxUZ8q9vHRcQZ6tLb0KwGHu8xjQHfYopZKLmnopQ anotherfake@key" ``` ## Encrypting your `.spin.yml` file It is possible that if you want to encrypt your `.spin.yml` file for security reasons, you can use the [`spin vault`](https://getspin.pro/docs/command-reference/vault) command which will use Ansible Vault to securely encrypt your file. If you do choose to encrypt your `.spin.yml` file, just be sure to add the `.vault-password` file so Ansible can securely decrypt it when it runs. [Learn more about "spin vault" →](https://getspin.pro/docs/command-reference/vault) # Create a Server with DigitalOcean ## Create an account The first step is to create an account with DigitalOcean. You can do this by going to their website and clicking the "Sign Up" button. With the link below, they offer $200 in credits. This is an affiliate link, meaning we get a small kickback if you sign up, but this doesn't affect our recommendations. [Sign Up with DigitalOcean →](https://m.do.co/c/f3bad4b927ca){rel=""nofollow""} ## Create an API token ::note This API token is very powerful and should be treated as a secret. Do not share this token and treat it like you would a password. :: To create an API token, you'll need to sign in to the [DigitalOcean Console](https://cloud.digitalocean.com/){rel=""nofollow""}. On the left sidebar, click on the "API" section. ![Go to DigitalOcean API](https://getspin.pro/images/docs/digitalocean/api-sidebar.png) On the API page, click the "Generate New Token" button. ![Generate DigitalOcean API Token](https://getspin.pro/images/docs/digitalocean/generate-token.png) You can set a number of settings for the token: - **Name**: Set this to something descriptive. - **Expiration**: Set how long the token should be valid for. The shorter the value, the more secure, but the more often you'll need to generate a new token. - **Scopes**: Select "Custom Scopes" for the most secure option. ![DigitalOcean API Token Scopes](https://getspin.pro/images/docs/digitalocean/token-scopes.png) If you choose "Custom Scopes", you can select the following permissions: ::note The "Full Access" scope is the easiest option, but it gives the token access to everything. Choose what makes the most sense for your use case. Use the custom scopes below for the most secure option. :: | Access Level | Scopes | Details | | ----------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | Fully Scoped Access | 10 scopes | - firewall (4): create, read, update, delete :br - regions (1): read :br - sizes (1): read :br - ssh\_key (4): create, read, update, delete | | Create Access | 4 scopes | project / tag / image / droplet | | Read Access | 5 scopes | snapshot / project / tag / image / droplet | | Update Access | 3 scopes | project / image / droplet | | **Total Custom Scopes** | **22 scopes** | | ## Place the token in your `.spin.yml` file In your `.spin.yml` file, you'll find a `providers` section where you can add your DigitalOcean API token. ```yaml [.spin.yml configure providers] ############################################################## # 👇 Providers - You must set at least one provider ############################################################## providers: - name: digitalocean api_token: abc123def456ghi789jkl012mno345pqr678stu901vwx234yz ``` ## Set as DO\_API\_TOKEN environment variable If you prefer to set the token as an environment variable, you can also set the `DO_API_TOKEN` variable in your `.env` file, secrets manager, or wherever you store your environment variables. ## Configure users Make sure you configure your system users in your `.spin.yml` file. [Learn more about users →](https://getspin.pro/docs/server-configuration/spin-yml-usage#users) ```yaml [Example users configuration in .spin.yml] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: - username: alice name: Alice Smith groups: ['sudo'] authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" ``` ## Configuring a DigitalOcean hardware profile By default we set you up with a very cost-effective hardware profile to get up and running quickly. ```yaml [.spin.yml default Hardware Profiles] ############################################################## # 🤖 Hardware Profiles ############################################################## hardware_profiles: # DigitalOcean - name: digitalocean_1c_1gb_ubuntu2404 provider: digitalocean profile_config: region: nyc3 size: s-1vcpu-1gb image: ubuntu-24-04-x64 backups: true ``` You can uncomment the defaults we give you or create/modify your own hardware profile. | Profile Config | Description | API Reference | | -------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `region` | The data center and location you want to deploy your server to (pick the closest one to your customers). | See below for common examples. | | `size` | The type of server. | See below for common examples. | | `image` | The image to use for the server. | [DigitalOcean Images](https://docs.digitalocean.com/reference/api/api-reference/#tag/Images){rel=""nofollow""} | | `backups` | Whether to enable snapshot backups for the server (may add 20% to the monthly price). | Learn more about [DigitalOcean snapshot backups](https://www.digitalocean.com/products/backups){rel=""nofollow""}. | ### Common Region Values The `region` value is the `slug` of the region. You can find the full list of regions [here](https://docs.digitalocean.com/reference/api/api-reference/#tag/Regions){rel=""nofollow""}. | Location | Country | Value | | --------------- | ----------- | ------ | | New York 1 | USA | `nyc1` | | New York 3 | USA | `nyc3` | | San Francisco 3 | USA | `sfo3` | | Amsterdam 3 | Netherlands | `ams3` | | Singapore 1 | Singapore | `sgp1` | | London 1 | UK | `lon1` | | Frankfurt 1 | Germany | `fra1` | | Toronto 1 | Canada | `tor1` | | Bangalore 1 | India | `blr1` | | Sydney 1 | Australia | `syd1` | ### Common Size Values ::note Make sure your server type is supported in the region you choose. Also, some of the pricing may change so be sure to check the latest pricing on the [DigitalOcean Droplet Pricing Page](https://www.digitalocean.com/pricing/droplets){rel=""nofollow""}. :: You can find the full list of server types [here](https://docs.digitalocean.com/reference/api/api-reference/#tag/Sizes){rel=""nofollow""}. | Server Type | vCPUs | RAM | Storage | Traffic | Monthly Price (USD) | Description | | -------------------------- | ----- | ---- | ------- | ------- | ------------------- | ------------- | | **Basic Droplets** | | | | | | | | `s-1vcpu-1gb` | 1 | 1GB | 25GB | 1TB | $6.00 | Basic | | `s-1vcpu-1gb-amd` | 1 | 1GB | 25GB | 1TB | $7.00 | Basic AMD | | `s-1vcpu-1gb-intel` | 1 | 1GB | 25GB | 1TB | $7.00 | Basic Intel | | `s-1vcpu-2gb` | 1 | 2GB | 50GB | 2TB | $12.00 | Basic | | `s-2vcpu-2gb` | 2 | 2GB | 60GB | 3TB | $18.00 | Basic | | `s-2vcpu-4gb` | 2 | 4GB | 80GB | 4TB | $24.00 | Basic | | `s-2vcpu-4gb-amd` | 2 | 4GB | 80GB | 4TB | $28.00 | Basic AMD | | `s-2vcpu-4gb-intel` | 2 | 4GB | 80GB | 4TB | $28.00 | Basic Intel | | **CPU-Optimized Droplets** | | | | | | | | `c-2` | 2 | 4GB | 25GB | 4TB | $42.00 | CPU-Optimized | | `c-4` | 4 | 8GB | 50GB | 5TB | $84.00 | CPU-Optimized | | `c-8` | 8 | 16GB | 100GB | 6TB | $168.00 | CPU-Optimized | | `c-16` | 16 | 32GB | 200GB | 7TB | $336.00 | CPU-Optimized | ## Configure your server By default, we give you defaults to get up and running quickly, but you might want to make some changes. [Learn more about server configuration →](https://getspin.pro/docs/server-configuration/spin-yml-usage#servers) ```yaml [Example server configuration in .spin.yml] ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: - server_name: ubuntu-1gb-nyc-1 environment: production hardware_profile: digitalocean_1c_1gb_ubuntu2404 ``` ## Provision your server Once you have everything ready, you can provision your server(s) by running this simple command: ```bash [Provision your server(s)] spin provision ``` This command will create your server(s) with DigitalOcean and configure your server(s) to be ready for deployment. There are many more options available when provisioning your server(s). To learn more see the guide below: [Learn more about "spin provision" →](https://getspin.pro/docs/command-reference/provision) ## Getting ready for deployment Now that you have a server ready, you'll want to learn how to get ready for deployment. Next steps are to choose a deployment strategy. [Learn which deployment strategy is right for you →](https://getspin.pro/docs/deployment/choosing-a-deployment-strategy) # Create a Server with Hetzner ## Create an account The first step is to create an account with Hetzner. You can do this by going to their website and clicking the "Sign Up" button. With the link below, they offer €⁠20 (\~$21 USD) credits free which can get you a server for a few months. This is an affiliate link, meaning we get a small kickback if you sign up, but this doesn't affect our recommendations. [Sign Up with Hetzner →](https://hetzner.cloud/?ref=lhLUIrkdUPhl){rel=""nofollow""} ## Create an API token To create an API token, you'll need to sign in to the [Hetzner Cloud Console](https://console.hetzner.cloud/){rel=""nofollow""}. Once signed in, select your project. ![Select Hetzner Project](https://getspin.pro/images/docs/hetzner/select-project.png) Inside of the project, look for the "Security" page on the left, then click "API Tokens" at the top. ![Hetzner API Tokens](https://getspin.pro/images/docs/hetzner/api-token-page.png) When you click "Generate API Token", you'll be presented with the option to select the scopes for the token. Select "Read & Write". ![Hetzner API Token Scopes](https://getspin.pro/images/docs/hetzner/generate-token.png) ::note This API token is very powerful and should be treated as a secret. Do not share this token and treat it like you would a password. :: ## Place the token in your `.spin.yml` file In your `.spin.yml` file, you'll find a `providers` section where you can add your Hetzner API token. ```yaml [.spin.yml configure providers] ############################################################## # 👇 Providers - You must set at least one provider ############################################################## providers: - name: hetzner api_token: abc123def456ghi789jkl012mno345pqr678stu901vwx234yz ``` ## Set as HCLOUD\_TOKEN environment variable If you prefer to set the token as an environment variable, you can also set the `HCLOUD_TOKEN` variable in your `.env` file, secrets manager, or wherever you store your environment variables. ## Configure users Make sure you configure your system users in your `.spin.yml` file. [Learn more about users →](https://getspin.pro/docs/server-configuration/spin-yml-usage#users) ```yaml [Example users configuration in .spin.yml] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: - username: alice name: Alice Smith groups: ['sudo'] authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" ``` ## Configuring a Hetzner hardware profile By default we set you up with a very cost-effective hardware profile to get up and running quickly. ```yaml [.spin.yml default Hardware Profiles] ############################################################## # 🤖 Hardware Profiles ############################################################## hardware_profiles: # Hetzner - name: hetzner_2c_2gb_ubuntu2404 provider: hetzner profile_config: location: ash server_type: cpx11 image: ubuntu-24.04 backups: true ``` You can uncomment the defaults we give you or create/modify your own hardware profile. | Profile Config | Description | API Reference | | -------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `location` | The data center and location you want to deploy your server to (pick the closest one to your customers). | See below for common examples. | | `server_type` | The type of server. | See below for common examples. | | `image` | The image to use for the server. | [Hetzner Images](https://docs.hetzner.cloud/#images-get-all-images){rel=""nofollow""} | | `backups` | Whether to enable snapshot backups for the server (may add 20% to the monthly price). | Learn more about [Hetzner snapshot backups](https://docs.hetzner.com/cloud/billing/faq#how-do-you-bill-for-snapshots-and-backups){rel=""nofollow""}. | ### Common Location Values The `location` value is the `name` of the location. You can find the full list of locations [here](https://docs.hetzner.cloud/#locations-get-all-locations){rel=""nofollow""}. | Location | Country | Value | | ------------- | --------- | ------ | | Falkenstein | Germany | `fsn1` | | Nuremberg | Germany | `nbg1` | | Helsinki | Finland | `hel1` | | Ashburn, VA | USA | `ash` | | Hillsboro, OR | USA | `hil` | | Singapore | Singapore | `sin` | ### Common Server Types ::note Make sure your server type is supported in the location you choose. Also, some of the pricing may change so be sure to check the latest pricing on the [Hetzner Cloud Pricing Page](https://www.hetzner.com/cloud/){rel=""nofollow""}. :: You can find the full list of server types [here](https://docs.hetzner.cloud/#server-types-get-all-server-types){rel=""nofollow""}. | Server Type | vCPUs | RAM | Storage | Traffic | Monthly Price (in EUR) | | -------------------------- | ----- | ----- | ------- | ------- | ---------------------- | | **Shared CPU - AMD (CPX)** | | | | | | | `cpx11` | 2 | 2GB | 40GB | 1TB | €4.99 | | `cpx21` | 3 | 4GB | 80GB | 2TB | €9.49 | | `cpx31` | 4 | 8GB | 160GB | 3TB | €16.49 | | `cpx41` | 8 | 16GB | 240GB | 4TB | €30.49 | | `cpx51` | 16 | 32GB | 360GB | 5TB | €60.49 | | **Dedicated CPU (CCX)** | | | | | | | `ccx13` | 2 | 8GB | 80GB | 1TB | €12.99 | | `ccx23` | 4 | 16GB | 160GB | 2TB | €25.99 | | `ccx33` | 8 | 32GB | 240GB | 3TB | €49.99 | | `ccx43` | 16 | 64GB | 360GB | 4TB | €99.99 | | `ccx53` | 32 | 128GB | 600GB | 6TB | €199.99 | ## Configure your server By default, we give you defaults to get up and running quickly, but you might want to make some changes. [Learn more about server configuration →](https://getspin.pro/docs/server-configuration/spin-yml-usage#servers) ```yaml [Example server configuration in .spin.yml] ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: - server_name: ubuntu-2gb-ash-1 environment: production hardware_profile: hetzner_2c_2gb_ubuntu2404 ``` ## Provision your server Once you have everything ready, you can provision your server(s) by running this simple command: ```bash [Provision your server(s)] spin provision ``` This command will create your server(s) with Hetzner and configure your server(s) to be ready for deployment. There are many more options available when provisioning your server(s). To learn more see the guide below: [Learn more about "spin provision" →](https://getspin.pro/docs/command-reference/provision) ## Getting ready for deployment Now that you have a server ready, you'll want to learn how to get ready for deployment. Next steps are to choose a deployment strategy. [Learn which deployment strategy is right for you →](https://getspin.pro/docs/deployment/choosing-a-deployment-strategy) # Create a Server with Vultr ## Create an account The first step is to create an account with Vultr. You can do this by going to their website and clicking the "Sign Up" button. With the link below, they offer $100 in credits. This is an affiliate link, meaning we get a small kickback if you sign up, but this doesn't affect our recommendations. [Sign Up with Vultr →](https://www.vultr.com/?ref=9627777-8H){rel=""nofollow""} ## Create an API token ::note This API token is very powerful and should be treated as a secret. Do not share this token and treat it like you would a password. :: To create an API token, you'll need to sign in to the [Vultr Console](https://my.vultr.com/){rel=""nofollow""}. Click on your name in the upper right, then click "API". ![Go to Vultr API](https://getspin.pro/images/docs/vultr/api-link.png) On the API page, click the "Enable API" button. ![Enable Vultr API](https://getspin.pro/images/docs/vultr/enable-api.png) You'll see your API token on the page. Press the "Copy" button to copy the token to your clipboard. ![Vultr API Token](https://getspin.pro/images/docs/vultr/api-token.png) ::note This token is like a password that has full access to your account. If you want to limit the API key by IP address, you can do so by adjusting the "Access Control" settings on the API page. :: ## Place the token in your `.spin.yml` file In your `.spin.yml` file, you'll find a `providers` section where you can add your Vultr API token. ```yaml [.spin.yml configure providers] ############################################################## # 👇 Providers - You must set at least one provider ############################################################## providers: - name: vultr api_token: abc123def456ghi789jkl012mno345pqr678stu901vwx234yz ``` ## Set as VULTR\_API\_KEY environment variable If you prefer to set the token as an environment variable, you can also set the `VULTR_API_KEY` variable in your `.env` file, secrets manager, or wherever you store your environment variables. ## Configure users Make sure you configure your system users in your `.spin.yml` file. [Learn more about users →](https://getspin.pro/docs/server-configuration/spin-yml-usage#users) ```yaml [Example users configuration in .spin.yml] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: - username: alice name: Alice Smith groups: ['sudo'] authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" ``` ## Configuring a Vultr hardware profile By default we set you up with a very cost-effective hardware profile to get up and running quickly. ```yaml [.spin.yml default Hardware Profiles] ############################################################## # 🤖 Hardware Profiles ############################################################## hardware_profiles: # Vultr - name: vultr_1c_1gb_ubuntu2404 provider: vultr profile_config: region: ord plan: vc2-1c-1gb os: "Ubuntu 24.04 LTS x64" backups: true ``` You can uncomment the defaults we give you or create/modify your own hardware profile. | Profile Config | Description | API Reference | | -------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | `region` | The data center and location you want to deploy your server to (pick the closest one to your customers). | See below for common examples. | | `plan` | The type of server. | See below for common examples. | | `os` | The image to use for the server. | [Vultr Images](https://www.vultr.com/api/#tag/images){rel=""nofollow""} | | `backups` | Whether to enable snapshot backups for the server (may add 20% to the monthly price). | Learn more about [Vultr snapshot backups](https://docs.vultr.com/vps-automatic-backups){rel=""nofollow""}. | ### Common Region Values The `region` value is the `id` of the region. You can find the full list of regions using the [Vultr API](https://www.vultr.com/api/#tag/region/operation/list-regions){rel=""nofollow""}. | Location | Country | Value | | ----------- | ----------- | ----- | | Amsterdam | Netherlands | `ams` | | Atlanta | USA | `atl` | | Bangalore | India | `blr` | | Chicago | USA | `ord` | | Dallas | USA | `dfw` | | Frankfurt | Germany | `fra` | | London | UK | `lhr` | | Los Angeles | USA | `lax` | | Mumbai | India | `bom` | | New Jersey | USA | `ewr` | | Paris | France | `cdg` | | Seoul | South Korea | `icn` | | Singapore | Singapore | `sgp` | | Sydney | Australia | `syd` | | Tokyo | Japan | `nrt` | | Toronto | Canada | `yto` | ### Common Plan Values You can find the full list of server types [here](https://www.vultr.com/api/#tag/plans/operation/list-plans){rel=""nofollow""}. ::note These prices can change at anytime. Be sure to check the latest pricing on the [Vultr Pricing Page](https://www.vultr.com/pricing/){rel=""nofollow""}. :: | Server Type | vCPUs | RAM | Storage | Traffic | Monthly Price (USD) | Description | | -------------------------------- | ----- | ---- | ------- | ------- | ------------------- | ------------- | | **Regular Performance** | | | | | | | | `vc2-1c-1gb` | 1 | 1GB | 25GB | 1TB | $5.00 | Basic SSD | | `vc2-1c-2gb` | 1 | 2GB | 55GB | 2TB | $10.00 | Basic SSD | | `vc2-2c-4gb` | 2 | 4GB | 80GB | 3TB | $20.00 | Basic SSD | | `vc2-4c-8gb` | 4 | 8GB | 160GB | 4TB | $40.00 | Basic SSD | | **High Performance (AMD/Intel)** | | | | | | | | `vhp-1c-1gb` | 1 | 1GB | 25GB | 2TB | $6.00 | NVMe SSD | | `vhp-1c-2gb` | 1 | 2GB | 50GB | 3TB | $12.00 | NVMe SSD | | `vhp-2c-4gb` | 2 | 4GB | 100GB | 5TB | $24.00 | NVMe SSD | | `vhp-4c-8gb` | 4 | 8GB | 180GB | 6TB | $48.00 | NVMe SSD | | **CPU Optimized** | | | | | | | | `vcp-2c-4gb` | 2 | 4GB | 75GB | 5TB | $40.00 | CPU Optimized | | `vcp-4c-8gb` | 4 | 8GB | 150GB | 6TB | $80.00 | CPU Optimized | | `vcp-8c-16gb` | 8 | 16GB | 300GB | 7TB | $160.00 | CPU Optimized | ## Configure your server By default, we give you defaults to get up and running quickly, but you might want to make some changes. [Learn more about server configuration →](https://getspin.pro/docs/server-configuration/spin-yml-usage#servers) ```yaml [Example server configuration in .spin.yml] ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: - server_name: ubuntu-1gb-ord-2 environment: production hardware_profile: vultr_1c_1gb_ubuntu2404 ``` ## Provision your server Once you have everything ready, you can provision your server(s) by running this simple command: ```bash [Provision your server(s)] spin provision ``` This command will create your server(s) with Vultr and configure your server(s) to be ready for deployment. There are many more options available when provisioning your server(s). To learn more see the guide below: [Learn more about "spin provision" →](https://getspin.pro/docs/command-reference/provision) ## Getting ready for deployment Now that you have a server ready, you'll want to learn how to get ready for deployment. Next steps are to choose a deployment strategy. [Learn which deployment strategy is right for you →](https://getspin.pro/docs/deployment/choosing-a-deployment-strategy) # Use Any Host with Spin ## Server Requirements Make sure your server and host meet the minimum server requirements. [View the Spin Server Requirements →](https://getspin.pro/docs/server-configuration/server-requirements) ## Ensure you're able to connect to your server via SSH Since you'll have to take care of the set up manually, ensure you can connect to your server via SSH. ```bash [Confirm SSH access] # Replace 1.2.3.4 with your server's IP address ssh root@1.2.3.4 ``` ## Configure users Make sure you configure your system users in your `.spin.yml` file. [Learn more about users →](https://getspin.pro/docs/server-configuration/spin-yml-usage#users) ```yaml [Example users configuration in .spin.yml] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: - username: alice name: Alice Smith groups: ['sudo'] authorized_keys: - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" ``` ## You can remove "providers" and "hardware\_profiles" if you want By default, the `.spin.yml` file includes some defaults for providers and hardware profiles. You can remove these if you want to use your own. ```yaml [❌ You can remove these lines if you want] # ############################################################## # # 👇 Providers - You must set at least one provider # ############################################################## # providers: # - name: digitalocean # api_token: Set token here OR delete this line and set environment variable DO_API_TOKEN # - name: hetzner # api_token: Set token here OR delete this line and set environment variable HCLOUD_TOKEN # - name: vultr # api_token: Set token here OR delete this line and set environment variable VULTR_API_KEY # ############################################################## # # 🤖 Hardware Profiles # ############################################################## # hardware_profiles: # # Hetzner # - name: hetzner_2c_2gb_ubuntu2404 # provider: hetzner # profile_config: # location: ash # server_type: cpx11 # image: ubuntu-24.04 # backups: true # # Vultr # - name: vultr_1c_1gb_ubuntu2404 # provider: vultr # profile_config: # region: ord # plan: vc2-1c-1gb # os: "Ubuntu 24.04 LTS x64" # backups: true # # DigitalOcean # - name: digitalocean_1c_1gb_ubuntu2404 # provider: digitalocean # profile_config: # region: nyc3 # size: s-1vcpu-1gb # image: ubuntu-24-04-x64 # backups: true ``` ## Set your server address under "servers" If you use our native providers with Spin, it will automatically create and populate the `address` property for you. Since in this case we're providing our own server, we'll need to set the `address` property for the server in the `.spin.yml` file. ```yaml [.spin.yml] ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: - server_name: my-awesome-server environment: production address: 1.2.3.4 # 👈 Be sure to set this to your server's IP address or DNS hostname # hardware_profile: hetzner_2c_2gb_ubuntu2404 (❌ You can comment or delete this line out) ``` You can use the IP address or hostname of your server. Feel free to remove the `hardware_profile` property if you do not plan to use any providers. ## Provision your server Once you have everything ready, you can provision your server(s) with the following command: ```bash [Provision your server(s)] spin provision -u root ``` ::note ⚠️ Most cloud providers (DigitalOcean, Vultr, Hetzner) use `root` as the default user. If your server uses a different sudo user, replace `root` with that username. :: To learn more about this process, see the guide below: [Learn more about "spin provision" →](https://getspin.pro/docs/command-reference/provision) ### Troubleshooting SSH Connection If you encounter connection issues, verify your SSH access first: ```bash [Verify SSH access] ssh root@1.2.3.4 # Replace with your username and server IP ``` You should be able to connect using SSH key authentication without being prompted for a password. ## Getting ready for deployment Now that you have a server ready, you'll want to learn how to get ready for deployment. Next steps are to choose a deployment strategy. [Learn which deployment strategy is right for you →](https://getspin.pro/docs/deployment/choosing-a-deployment-strategy) # Choosing a Deployment Strategy ## Types of Deployments There are two types of deployments: 1. **Simple Deployments from your local machine** - We can use the [`spin deploy`](https://getspin.pro/docs/command-reference/deploy) command to deploy your application from your local machine to your server. 2. **Automated Deployments** - You can use our GitHub Actions to help you automatically deploy your application when you push to GitHub. | | spin deploy | GitHub Actions | | ------------------------- | --------------- | ---------------------------------------------------- | | Difficulty | Very Easy | Basic Understanding of SSH & GitHub Actions required | | Team Size | Solo-developers | Small to very large teams | | Zero-downtime Deployments | ✅ | ✅ | | Automated Deployments | ❌ | ✅ | Automated deployments are recommended for teams because they standardize the deployment process without human interaction. If you're a solo developer, you may find that [`spin deploy`](https://getspin.pro/docs/command-reference/deploy) is so easy to use you'll never need to learn the complexities of CI/CD or GitHub Actions. ## Simple Deployments from your local machine To learn more about our simple deployments from your local machine, see the guide below. [Simple Deployments from your local machine →](https://getspin.pro/docs/deployment/using-spin-deploy) ## Automated Deployments with GitHub Actions To learn more about our automated deployments, see the guide below. [Automated Deployments with GitHub Actions →](https://getspin.pro/docs/deployment/automated-deployments-with-github-actions) ## Preparing an `.env.` file Regardless of the deployment strategy you choose, you'll need to prepare an `.env.` file that will be used to deploy your application. [Learn how to prepare your `.env.` file →](https://getspin.pro/docs/deployment/preparing-env-file) # Preparing an .env. file ## What is an .env. :environment[ file?] An `.env.` file is a file that contains environment variables for a specific environment. For example, if you are deploying to your `production` environment, you would create an `.env.production` file. ## Variables to set in your .env. :environment[ file] The easiest way to create an `.env.` file is to copy your `.env` file and rename it to `.env.`. You don't want reuse secrets across files, you should change credentials across environments. You will want to make the changes below (the ones that are applicable to your application): | Variable | Description | Example Format | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `APP_ENV` | Set your environment name. | `production` | | `APP_DEBUG` | Set this to `false` (for any world-exposed application). | `false` | | `APP_KEY` | You can use `php artisan key:generate` to generate a new key or [use this online tool](https://generate-random.org/laravel-key-generator){rel=""nofollow""}. | `base64:...` | | `DB_DATABASE` | Set this to the name of your database. Use simple names and avoid weird characters. | `my-database` | | `DB_USERNAME` | Set this to the username that will have access to your database. | `myusername` (⚠️ Do NOT use `root` or `admin`) | | `DB_PASSWORD` | Set this to the password for the username that will have access to your database. | `mysupers3curepassword` (⚠️ Avoid special characters. [Use long alphanumeric strings instead](https://www.random.org/strings/?num=100&len=26&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""}) | | `REDIS_PASSWORD` | Set the password for your Redis database. | `mys3cureredispassword` (⚠️ Avoid special characters. [Use long alphanumeric strings instead](https://www.random.org/strings/?num=100&len=26&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""}) | | `REVERB_HOST` | The DNS hostname to use for Reverb. (⚠️ must be different than your `SPIN_APP_DOMAIN`) | `socket.example.com` | ## Special Notes on database credentials ::note **⚠️ NOTE: If you change the credentials in your `.env` file after you've already started the database, the database will not automatically update to your new credentials.** You'll have to manually update the credentials in the database itself. Refer to the official Docker image documentation for the database you're using for more details. :: The default behavior of Postgres, MySQL, Redis, and MariaDB are to use the credentials on **first initialization**. This means if you change the credentials in your `.env` file after you've already started the database, the database automatically update the username or password of the users in your `.env` file. To make a change, you'll need to use the methods described in their official documentation on how to manage users and passwords. You'll need your existing credentials to make the changes and then you'll need to update the credentials in your `.env` file to match the new credentials. If you're just getting started with Spin and you deployed to a new server and just learned this the hard way (been there many times 😃), then you may consider just "[Starting Over](https://getspin.pro/docs/server-access/troubleshooting-your-application#starting-over)" by deleting your entire Docker data, changing your `.env` file, and then redeploying. # Automating Deployments with GitHub Actions ## Video Overview We have a video that goes over this process in more detail. :video-embed{src="https://www.youtube.com/watch?v=9dfW2eI9Joo"} ## Default Behavior By default, Spin Pro comes with a GitHub Actions workflow that will deploy your application to your server when you push to your `main` branch in your repository. This workflow is located in the `.github/workflows` directory of your repository. You can customize this workflow to fit your needs. ## Prepare an `.env.` file Make sure you don't miss the process of preparing your `.env.` file. Ensure this is done before moving forward. [Learn how to prepare your `.env.` file →](https://getspin.pro/docs/deployment/preparing-env-file) ## Create a GitHub Repository and prepare for deployment Once we have an environment variable file created, we can create a GitHub repository for our app right from the CLI using the GitHub CLI with [`spin gh`](https://getspin.pro/docs/command-reference/gh). ::note Run these commands in the root of your project directory. :: ```bash [Create a GitHub repository] spin gh repo create # Make sure to push an an EXISTING repository (since we initialize a Git repo for you) ``` ::note If you're not already using GitHub CLI, you may be prompted to login. If so, you can run [`spin gh auth login`](https://cli.github.com/manual/gh_auth_login){rel=""nofollow""} to login. :: ## Configure GitHub Actions Secrets/Environment Variables In order for deployments to work automatically with our GitHub Actions workflows, we need to configure secrets and environment variables in GitHub Actions. You can do this manually via the UI, but we found it a lot easier to combine this all into an automated process. ```bash [Configure GitHub Actions Secrets/Environment Variables] spin configure gha ``` ::note If you need to make changes to your `.env.` file or anything else, just run the `spin configure gha ` command again. It will automatically update the GitHub Actions secrets and ensure they are up to date. :: The above command takes out all the heavy lifting for you and will upload your environment variables to GitHub Actions. You can verify their existence by going to the `Settings` tab in your GitHub repository and then clicking on `Secrets and variables` then `Actions`. Once `spin configure gha ` completes, you're now ready for deployment! 🚀 ## Running a deployment To run a deployment, you simply need to push your changes to your repository. By default, any code pushed to `main` will trigger a deployment to "production." ```bash [Running a deployment] git push origin main ``` ### Changing the deployment trigger Some teams may want to change the default deployment trigger. For example, instead of deploying to production when you push to `main`, you may want to use "release" triggers. You'll see in the default triggers by looking at the `on` section of the workflow file. Refer to the [GitHub Actions documentation](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#on){rel=""nofollow""} for more information if you'd like to change the trigger. If you'd like advanced customization, refer to the following GitHub Actions that we've created: - [serversideup/github-action-docker-swarm-deploy](https://github.com/serversideup/github-action-docker-swarm-deploy){rel=""nofollow""} - [serversideup/github-action-docker-build](https://github.com/serversideup/github-action-docker-build/){rel=""nofollow""} You can also refer to the [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions){rel=""nofollow""} document if you'd like even more customization options. ## Where to watch the status of your deployment You can watch the status of your deployment by going to the `Actions` tab in your repository. You can see the status of the deployment and any logs that are generated. ::responsive-image --- maxWidth: 500 alt: Watching the status of your deployment in GitHub Actions src: https://getspin.pro/images/docs/gha-deployment.png --- :: ## Using self-hosted runners to improve security If you'd like to improve the security of your deployments, you can use self-hosted runners. This will allow you to run your deployments on your own infrastructure instead of GitHub's infrastructure. You can learn more about self-hosted runners in the [GitHub Actions documentation](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners){rel=""nofollow""}. Once you have a self-hosted runner set up, you can use a firewall to limit SSH access to your server only from IP addresses that are associated with your self-hosted runner and a dedicated VPN for your team. ## Viewing the deployment Once your deployment is complete, you can visit your application that you set with the `APP_URL` environment variable in your `.env.` file. If everything works, you should see your application! 🥳 ## Connecting to your server If you need to connect to your server, you can: - [Connect to your server via SSH](https://getspin.pro/docs/server-access/connecting-to-your-server) - [Connect to your database](https://getspin.pro/docs/advanced/connecting-to-your-database) If things didn't work, see our [troubleshooting guide](https://getspin.pro/docs/server-access/troubleshooting-your-application). # Using "spin deploy" ## When "spin deploy" is the right choice We created `spin deploy` for the solo developer who wants an easy way to quickly deploy their application without the burden of learning CI/CD or GitHub Actions. If you're on a larger team or share your application with many developers, we highly recommend coming up with an [automated deployment strategy](https://getspin.pro/docs/deployment/automated-deployments-with-github-actions). ## How "spin deploy" works It's quite brilliant how `spin deploy` works. When you run this command, it will build your application locally with Docker, upload it to a temporary registry running on your machine, establish an SSH tunnel to your server, then have your server pull the new image from your local machine without any downtime. All of this is completed in one command without you needing to know how to configure Docker registries, CI/CD tools, or anything else. 🤯 ![Spin Deploy](https://getspin.pro/images/docs/whats-spin/spin-deploy.png) ## Prepare an `.env.` file Make sure you don't miss the process of preparing your `.env.` file. Ensure this is done before moving forward. [Learn how to prepare your `.env.` file →](https://getspin.pro/docs/deployment/preparing-env-file) ## Learn more about "spin deploy" To learn more about the `spin deploy` command, see the guide below. [Learn more about "spin deploy" →](https://getspin.pro/docs/command-reference/deploy) ## Viewing the deployment Once your deployment is complete, you can visit your application that you set with the `APP_URL` environment variable in your `.env.` file. If everything works, you should see your application! 🥳 ## Connecting to your server If you need to connect to your server, you can: - [Connect to your server via SSH](https://getspin.pro/docs/server-access/connecting-to-your-server) - [Connect to your database](https://getspin.pro/docs/advanced/connecting-to-your-database) If things didn't work, see our [troubleshooting guide](https://getspin.pro/docs/server-access/troubleshooting-your-application). # Connecting to Your Server ## Connect to your server To connect to your server, you can use the `spin ssh` command. ```bash [Connect to your server] ssh @
``` If you use the same username on your host machine as the username on your server, you can omit the username from the command. You can figure out your username by running `whoami` in a new terminal session on your local machine. ## Deploying your application to your server To deploy the application to your server, you can choose between different deployment strategies. [Learn more about deployment strategies →](https://getspin.pro/docs/deployment/choosing-a-deployment-strategy) ## Troubleshooting your application If you run into any issues with your application, we've compiled a guide to help you view and troubleshoot your application. [Troubleshooting your application →](https://getspin.pro/docs/server-access/troubleshooting-your-application) ## Updating your server Keeping your server up to date is important for security and performance. We've compiled a guide to show how easy it is to update your server. [Updating your server →](https://getspin.pro/docs/server-access/updating-your-server) # Troubleshooting Your Application ::note Before running any of these commands, you'll need to [connect to your server](https://getspin.pro/docs/server-access/connecting-to-your-server). :: ## View Docker Services Whenever you deploy a container with Docker, they are grouped into units called "services". Services could be things like databases, web servers, queues, etc. ```bash [View Docker services] sudo docker service ls ``` [Learn more about "docker service ls" →](https://docs.docker.com/reference/cli/docker/service/ls/){rel=""nofollow""} ## View Docker Service Logs When you list out your services, you can now view the logs of that service. ::note If you want to view the logs in real-time, you can use the `-f` flag. :: ```bash [View Docker service logs] sudo docker service logs ``` [Learn more about "docker service logs" →](https://docs.docker.com/reference/cli/docker/service/logs/){rel=""nofollow""} ## Running commands in a running container Sometimes you might need to do some troubleshooting in a running container. To do this, we need to follow this process: 1. Determine the *running* container ID for the service. 2. Use `docker exec` (with a TTY and interactive mode) attach to the shell of the running container. We will use [`docker ps`](https://docs.docker.com/reference/cli/docker/ps/){rel=""nofollow""} to get the container ID, then use [`docker exec`](https://docs.docker.com/reference/cli/docker/exec/){rel=""nofollow""} to open a shell to the container. ```bash [Open a shell to a running container] # Get the container ID of the running service sudo docker ps --filter "name=" --format "{{.ID}}" # Run a command in the running container (you can replace "sh" with any command) # but by default, this will open a shell to the container (type "exit" to close) sudo docker exec -it sh ``` This is a two step process, but if you want to do this in a single command, we can use this trick below: ```bash [Open a shell to a running container (single command)] # Replace with the name of your service. This will run `sh` in the first container ID it finds. # You can change `sh` to `bash` if your container. Bash will give you a better experience. sudo docker exec -it $(sudo docker ps --filter "name=" --format "{{.ID}}" | head -n 1) sh ``` We're able to run this in a single command because we're using a subshell to get the container ID and then passing that to the `docker exec` command. If you don't need a shell and you want to run something like `php artisan migrate`, you would just replace `sh` with `php artisan migrate`. Just make sure your container is running commands relative to the directory you want to run the command in. Sometimes it's best to just open a shell and navigate to the directory you want to run the command in. ## Viewing application logs When you're viewing application logs, you might have multiple places to look depending on the configuration of your application and what output you're trying to look for. 1. **Docker Swarm Service Logs** - The output here will be more server centric. Meaning you'll see deeper services logs such as PHP, FPM, Nginx, etc. 2. **Application Logs** - The output here will be more application centric. Meaning you'll see logs from your application itself. 3. **Error Tracking Services** - If you're using a logging service like Sentry or GlitchTip (which we highly recommend), you'll want to check those logs as well. These services will also alert you if there are any critical errors happening in your application. ## Viewing Laravel Logs If you don't use an error tracking service like Sentry or GlitchTip, Laravel 11 by default will log to the `storage/logs/laravel.log` file. You can access that by running a command like this: ```bash [View Laravel logs] # Find the service name of your application sudo docker service ls # Open a shell to the first container ID returned from your service sudo docker exec -it $(sudo docker ps --filter "name=" --format "{{.ID}}" | head -n 1) sh # View the available log files ls storage/logs/ # View the laravel.log file cat storage/logs/laravel.log ``` You can see it's a bit of a process to get to the log file, so that's why we recommend using an error tracking service like Sentry or GlitchTip which you can self-host for no cost if you wanted. ## Enabling Debug Mode Depending on the service you're troubleshooting, the official documentation for the Docker image you're using may have instructions on how to enable debug mode. For example, if you're running `serversideup/php:8.4-fpm-nginx`, [the official documentation](https://serversideup.net/open-source/docker-php/docs/reference/environment-variable-specification){rel=""nofollow""} talks about setting `LOG_OUTPUT_LEVEL=debug`. In this example, we would just send up a commit with the environment variable set. ::note Only use debug modes if you're actively troubleshooting an issue. Debug mode will log a lot of information to your logs which can slow down your application and use a lot of disk space. :: ```yml [Set the LOG_OUTPUT_LEVEL docker-compose.prod.yml file] services: php: image: ${SPIN_IMAGE_DOCKERFILE_PHP} environment: LOG_OUTPUT_LEVEL: debug ``` ## Services won't start or are not accessible When services won't start or they are not accessible, they are usually broken down into two categories: 1. The container or service fail to start 2. The container or service is running, but you can't access it through HTTP/HTTPS ### Types of Health Checks When you're running applications with zero-downtime deployments, everything depends on health checks. There are **multiple levels** of health checks, so make sure you reference above to determine where your issue might be: 1. The Docker Swarm health check (the container or service fails to start) 2. The reverse proxy health check (the container or service is running, but you can't access it through HTTP/HTTPS) ### Docker Health Check The Docker health check is a health check that is more native to the container itself. Container authors can set [`HEALTHCHECK`](https://docs.docker.com/reference/dockerfile/#healthcheck){rel=""nofollow""} instructions in their `Dockerfile` to control the health of the container. Health checks can also be overridden by the Docker Swarm service configuration at with the [`healthcheck`](https://docs.docker.com/reference/compose-file/services/#healthcheck){rel=""nofollow""} option. One of the most frustrating things might be you try using the `docker service logs` command, but the service doesn't have any logs because the service doesn't exist yet. To get around this, we can use the [`docker service ps`](https://docs.docker.com/reference/cli/docker/service/ps/){rel=""nofollow""} command to get more information on why a container won't start. ```bash [Get more information on why a container won't start] sudo docker service ps --no-trunc ``` The above command will show a glimpse of why a container won't start. If everything looks normal there, you might want to inspect the service with [`docker service inspect`](https://docs.docker.com/reference/cli/docker/service/inspect/){rel=""nofollow""} to see if there are any other issues. ```bash [Inspect a Docker service] sudo docker service inspect --pretty ``` Adding the `--pretty` flag will show nice output of the service configuration and you can look for clues to see why the service might not be starting. ```bash [Example of a Docker health check failure] task: non-zero exit (137): dockerexec: unhealthy container ``` If you see an error message like the one above, this means something in the container is causing the Docker health check to fail. This could be caused by a start up script failing, a configuration issue, or something else. Start up scripts can be tricky to debug because if any of the scripts send a "non-zero exit" code, the Docker health check could fail. Make sure you're properly handling exit codes and testing your scripts in all scenarios. To get more information, put your container image in debug mode or add verbose logging and try again. You may get more information from `docker service logs` or `docker service inspect`. ::note If the container you're debugging is **serversideup/php**, you can set container image to debug mode by setting the `LOG_OUTPUT_LEVEL` environment variable to `debug` to get more information. :: ### Reverse Proxy Health Check If you're trying to access your application through HTTP/HTTPS, but you're getting a 503 or 404 error, it's likely something is wrong with the reverse proxy health check. For our default configurations, we use [Traefik](https://doc.traefik.io/traefik/){rel=""nofollow""} as the reverse proxy, so we'll give you a few tips on how to proceed with troubleshooting. ::note The example below shows a **broken configuration**. Don't copy from it. Let's learn from it instead. 😃 :: ```yml [Example of a broken configuration] services: php: image: ${SPIN_IMAGE_DOCKERFILE} environment: SSL_MODE: "full" deploy: labels: - "traefik.enable=true" - "traefik.http.routers.my-php-app.rule=Host(`${SPIN_APP_DOMA1N}`)" - "traefik.http.routers.my-php-app.entrypoints=websecure" - "traefik.http.routers.my-php-app.tls=true" - "traefik.http.routers.my-php-app.tls.certresolver=letsencryptresolver" - "traefik.http.services.my-php-app.loadbalancer.server.port=8080" - "traefik.http.services.my-php-app.loadbalancer.server.scheme=http" # Health check - "traefik.http.services.my-php-app.loadbalancer.healthcheck.path=/invalid" - "traefik.http.services.my-php-app.loadbalancer.healthcheck.interval=30s" - "traefik.http.services.my-php-app.loadbalancer.healthcheck.timeout=1s" - "traefik.http.services.my-php-app.loadbalancer.healthcheck.scheme=http" ``` #### Invalid Host I have a typo in my Host rule: `Host(`${SPIN\_APP\_DOMA1N}`)"` Since the variable is `SPIN_APP_DOMAIN`, I have a typo and used `SPIN_APP_DOMA1N` instead. This would cause a `404` error because the host is invalid and the variable is undefined. To fix this I would need to fix my typo and ensure `SPIN_APP_DOMAIN` is properly defined. #### Invalid Port + Scheme If I look at the documentation of [`serversideup/php`](https://serversideup.net/open-source/docker-php/docs/customizing-the-image/configuring-ssl){rel=""nofollow""}, you can see I have `SSL_MODE: "full"` set in the service configuration. This tells the application to use HTTPS. However, there are 4 issues with the configuration because of this change: - `server.port=8080`: The docs say this should be changed to `8443` when `SSL_MODE: "full"` is set. - `server.scheme=http`: Since we're using HTTPS, this should be set to `https`. - `healthcheck.timeout=1s`: This health check timeout is quite low. This could cause a health check failure if the application takes longer than 1 second to start. - `healthcheck.scheme=http`: The health check definition is different from the server definition. The health check should use `https`. - `healthcheck.path=/invalid`: If I don't have a page at `/invalid`, this will cause a health check failure. I can read the serversideup/php docs to set this to `/healthcheck` to use the native container health check endpoint or `/up` if I am running Laravel. Wow, you can see how many moving parts it takes to get zero-downtime deployments working. This process is true regardless of any service that you're running, so it's important to understand how each piece works together. Always remember: - Start with the service, check to make sure your application is actually getting deployed - Then check the reverse proxy configuration. - The health check MUST return a `200` status code to pass. Things like `301` or `302` redirects can cause the health check to fail. - Always refer to the official documentation of the Docker image you're using for looking for proper health check definitions. ::note If you want the "easy button" and you want a turn-key solution, look into [Spin Pro](https://getspin.pro){rel=""nofollow""}. We include everything you need to deploy Laravel quickly, reliably, and easily. Everything we talk about above is configured for you automatically. :: ## Database connection issues A common thing we also see are people who have connection issues. This is usually caused by: 1. The database service isn't ready by the time a script in your other container tries to access it (controlled by container [start orders](https://docs.docker.com/compose/how-tos/startup-order/){rel=""nofollow""}). 2. The host is invalid, like `localhost` or `127.0.0.1`, instead of using the name of the database service in their Docker Compose file (like `postgres`). 3. The credentials in the `.env` file get changed and the application can't connect to the database. If you're provisioning a database like Postgres, MariaDB, or MySQL, they make an environment variable available called `POSTGRES_USER` and`POSTGRES_PASSWORD` (or similar) that you can use to connect to the database. ::note Any of these `*_USER` or `*_PASSWORD` variables will provision **on initialization only**. If you change your `.env` to use a new password, the database will not automatically update the password. :: To fix this, you'll need to reference the documentation of your database engine to manually change the password. ### Diagnosing connection issues between services If you notice connection errors between services, make sure your `.env` file has the correct values. Special things to double check: - Ensure your `DB_HOST` (or comparable like `REDIS_HOST`) is set to the service name (ie. `mariadb`, `redis`, and NOT `127.0.0.1` or `localhost`) - Ensure your environment variable values don't have any weird special characters in them. - Ensure your `APP_URL` in `.env.` is set correctly (ie. `https://app.example.com`). - Ensure any services have strong passwords set. Sometimes default passwords are rejected for security reasons. You can use a number of online tools to [generate a strong password for your service](https://www.random.org/strings/?num=100&len=26&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""}. ## Stopping a service If you need to stop a service, you can use the `docker service rm` command. For example, to stop a service named `my-service`, you can run: ```bash [Stop a service] sudo docker service rm my-service ``` Replace `my-service` with the name of the service you want to stop. ## Removing volumes Volumes are used to persist data in your containers. If you need to remove a volume, you can use the `docker volume rm` command. For example, to remove a volume named `my-volume`, you can run: ```bash [Remove a volume] sudo docker volume rm my-volume ``` Replace `my-volume` with the name of the volume you want to remove. You can find the volume name by running `sudo docker volume ls`. ## Removing Swarm configurations If you need to remove a Swarm configuration, you can use the `docker config rm` command. For example, to remove a configuration named `my-config`, you can run: ```bash [Remove a configuration] sudo docker config rm my-config ``` Replace `my-config` with the name of the configuration you want to remove. You can find the configuration name by running `sudo docker config ls`. ## Removing networks If you need to remove a network, you can use the `docker network rm` command. For example, to remove a network named `my-network`, you can run: ```bash [Remove a network] sudo docker network rm my-network ``` ## Pruning unused resources If you need to remove unused resources, you can use the `docker system prune` command. For example, to remove all stopped containers, unused networks, and dangling images, you can run: ```bash [Prune unused resources] sudo docker system prune ``` This command removes all stopped containers, unused networks, and dangling images. You can add the `--all` flag to remove all unused images as well. This will free up disk space on your server. ## Starting over We've all been there. The process of learning sometimes can start with a "redo". The good news is since everything is containerized, everything is designed to be **disposable and repeatable**. Since we're running Docker, we *do not* need to rebuild the server. We can simply remove the Docker data and start over with a fresh deployment. ::note The commands below will destroy all data. This means things like databases, logs, etc will all be deleted and you'll have a fresh Docker environment to deploy to. :: ```bash [Delete all docker data and start over] sudo docker service rm $(sudo docker service ls -q) # Remove all services sudo docker stop $(sudo docker ps -aq) # Stop all containers sudo docker rm $(sudo docker ps -aq) # Remove all containers sudo docker system prune --all # Remove all unused images and networks sudo docker volume rm $(sudo docker volume ls -q) # Remove all volumes sudo docker config rm $(sudo docker config ls -q) # Remove all configurations ``` Run the commands above individually to ensure everything is removed properly. Once you've verified everything is removed, you can deploy a fresh copy of your application. ## Re-provisioning servers from scratch Sometimes you may want to completely delete a server from your cloud provider and start fresh with a new one. This is common when: - You ran into issues during initial provisioning and want to start over - You're testing your infrastructure setup - You want to move to a different server type or location When you delete a server from your cloud provider (like Hetzner, DigitalOcean, or Vultr) and want to re-provision, you'll need to clean up a few things first. ### Step 1: Remove the IP address from `.spin.yml` When Spin provisions a server through a provider, it automatically updates your `.spin.yml` file with the server's IP address. If you delete the server and want Spin to create a new one, you need to remove this `address` property. ```yaml [Before - Server with IP address assigned] servers: - server_name: ubuntu-2gb-ash-1 environment: production hardware_profile: hetzner_2c_2gb_ubuntu2404 address: 123.45.67.89 # Remove this line ``` ```yaml [After - Server ready for re-provisioning] servers: - server_name: ubuntu-2gb-ash-1 environment: production hardware_profile: hetzner_2c_2gb_ubuntu2404 ``` ### Step 2: Remove the server from SSH known\_hosts Your local machine stores SSH host keys for servers you've connected to. When you create a new server, it will have a different host key, which causes SSH to show a warning about a potential security issue. To remove the old host key entry, run: ```bash [Remove server from known_hosts] ssh-keygen -R your.server.ip.address ``` Replace `your.server.ip.address` with the IP address or hostname of the server you deleted. For example: ```bash [Example removing a specific IP] ssh-keygen -R 123.45.67.89 ``` ::note If you used a hostname to connect to your server, you may need to remove both the hostname and IP address entries. :: ```bash [Example removing a hostname and IP address] ssh-keygen -R myserver.example.com ssh-keygen -R 123.45.67.89 # Remove the IP address entry ``` ### Step 3: Re-provision your server Once you've cleaned up the `.spin.yml` file and SSH known\_hosts, you can provision a fresh server: ```bash [Provision a new server] spin provision ``` Spin will create a new server with your cloud provider and update your `.spin.yml` file with the new IP address. # Updating Your Server ## Background Running an out of date server stack can lead to security vulnerabilities and performance issues. Spin makes it easy to keep your server up to date. There are two categories of updates: - Application Stack Updates - Server Updates `spin maintain` focuses on *server updates*. Here's a quick look at what that looks like: ![Spin Maintain Command](https://getspin.pro/images/docs/whats-spin/spin-maintain.png) ### Application Stack Updates What we mean by application stack updates are things like Redis, Postgres, Node, PHP, etc. These are things you'll want to look at in your `docker-compose.*.yml`, `composer.json`, `package.json`, etc. Whenever you make a change, it will be version controlled so you can easily test and revert if needed. ### Server Updates Server updates are things like the underlying operating system, Docker, etc. It's important to keep these packages up to date as well. Thankfully Spin includes the [`spin maintain`](https://getspin.pro/docs/command-reference/maintain) command which will take care of the heavy lifting for you. ::note When you perform maintenance on your server, your server may experience brief downtime if it the updates require a reboot. Be sure to run this command during a communicated maintenance window. :: ```bash [Upgrade your servers] # Update all servers spin maintain # Update a specific environment spin maintain production ``` The above command will: - Connect to your server(s) - Update the all operating system packages - Update Docker - Reboot the server (if needed) # Generating a Secure SSH Key A few things about that will make this key secure: 1. The [ED25519 encryption](https://ed25519.cr.yp.to/){rel=""nofollow""} algorithm 2. A password protected key (if you password protect your key, you may need to go through additional steps to configure your SSH agent) If you want to nerd out on why we suggest this algorithm, you can [read this guide](https://blog.g3rt.nl/upgrade-your-ssh-keys.html){rel=""nofollow""}. ## 👨‍💻 Generating an SSH key ::note If you're using services like GitHub already, there's a good chance you already have a key like this. All you need is the **public key** value of your existing SSH key pair. You can likely find this in your `~/.ssh` directory, and look for files ending in `*.pub`. Spin works with any valid SSH key. It does NOT need to be the ED25519 algorithm, just as long as it works with SSH and is secure. :: If you need to create an SSH key, you can run this on your local machine: ```bash [Generate an SSH key] ssh-keygen -o -a 100 -t ed25519 ``` It will create two files: ```bash [Files created] ~/.ssh/id_ed25519 # ❌ This is your PRIVATE key. Keep this secret ~/.ssh/id_ed25519.pub # ✅ This is your PUBLIC key. This is the value we want to use ``` To get the public key value, you can run this command: ```bash [Get the public key value] cat ~/.ssh/id_ed25519.pub ``` This will echo the public key value to your terminal. ## What to do with this key You can copy this value and use it in your `.spin.yml` [when you configure your "users.username.authorized\_ssh\_keys" for your server](https://getspin.pro/docs/server-configuration/spin-yml-usage#users). # Configuring DNS records for your app ## Register a domain name In order for your domain to exist in the Internet, you'll need choose where to register your domain name. The vendor your choose is called a registrar. #### Popular registrars - [Cloudflare](https://domains.cloudflare.com/){rel=""nofollow""} - [Namecheap](https://www.namecheap.com/){rel=""nofollow""} Once you have your domain registered, we can now move forward with configuring our DNS records (think of DNS records as the phone book of the Internet). ## Configure DNS records In this example, we'll be using Cloudflare. Assuming that you've [already provisioned a server](https://getspin.pro/docs/server-configuration/server-configuration-basics), we can use the `address` field in our [`.spin.yml`](https://getspin.pro/docs/server-configuration/spin-yml-usage) file to help us configure our DNS records. ```yaml [Server IP Address in .spin.yml] servers: - server_name: ubuntu-2gb-ash-1 environment: production hardware_profile: hetzner_2c_2gb_ubuntu2404 address: 1.2.3.4 ``` Whenever you see the `address` field in the `.spin.yml` file, we can assume that server is provisioned with that IP address. In this example, we will want to copy `1.2.3.4` and add it to our DNS records. ## Add the IP address to your DNS records To add the IP address to your DNS records, you'll need to [login to your Cloudflare account](https://dash.cloudflare.com/){rel=""nofollow""} and add the IP address to your DNS records. ![Add the IP address to your DNS records](https://getspin.pro/images/docs/cloudflare-add-record.png) When you're signed in, you'll want to go to the `DNS` tab and click the `Add record` button. You'll see there are a few different inputs we need to set: ::note You may need to repeat this process for each domain you want to use. (For example, `www.ssudemo.com`, `ssudemo.com`, `reverb.ssudemo.com`, etc.) :: | Field | Description | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Type | The type of record we want to create. In this case, we want to create an `A` record. | | Name | The name of the record. If we want `app.ssudemo.com`, this value will be `app`. If we want to just use `ssudemo.com`, this value will be `@`. | | Value | The IP address we want to use for our record. In this case, we want to use `1.2.3.4`. | | Proxy Status | It is your choice to have this enabled or disabled. If you choose to have it enabled, Cloudflare will act as a proxy between your domain and the Internet. If you choose to have it disabled, Cloudflare will send traffic directly to the IP address. If you do enable the proxy, just remember you have Cloudflare cache that may need to be flushed on deployments. | Once you add the record, you should see something like this: ![DNS record added](https://getspin.pro/images/docs/cloudflare-record.png) ## Verify the DNS records To verify the DNS records, you can use the `dig` command. ```bash [Verify the DNS records] dig +short app.ssudemo.com ``` ::note If you have CloudFlare proxy enabled, it will return the CloudFlare Proxy IP address instead of `1.2.3.4` like in the example above. :: ```bash [Dig output with CloudFlare proxy enabled] ~> dig +short a app.ssudemo.com # Output 104.21.82.172 172.67.160.61 ``` ## CloudFlare Only: Configure SSL Mode If you decide to use CloudFlare as a proxy (add a record with the orange cloud icon) you may need to configure CloudFlare's SSL mode to work with your app. When CloudFlare makes a request to your app, we want to ensure it's making it over SSL. ![CloudFlare SSL mode](https://getspin.pro/images/docs/cloudflare-proxy.png) To change your SSL mode: 1. Login to the [CloudFlare Dashboard](https://dash.cloudflare.com/){rel=""nofollow""} 2. Click on your domain 3. Under **SSL/TLS encryption**, click **Configure** 4. Choose **Select** under "Custom SSL/TLS" 5. Select **Full** or **Full (Strict)** for your SSL mode (only select "Full (Strict)" if you have a valid SSL certificate, most of the time your first provision will be "Full") 6. Click **Save** [Learn more about CloudFlare's SSL mode →](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/){rel=""nofollow""} # Configuring your hosts file ::note We're looking to automate this functionality in the future, but we're very adamant about having it work across all operating systems without advanced customizations. We've seen a few solutions, but they require too much setup and are not user-friendly. If you have any ideas, [we'd love to hear your thoughts →](https://github.com/serversideup/spin/discussions){rel=""nofollow""} :: ## What is a Hosts File? A hosts file is a simple text file that maps IP addresses to domain names. When you type a domain name into your browser, your computer checks the hosts file to see if it has an IP address for that domain. If it does, it uses that IP address to connect to the server. If it doesn't, it will use a DNS server to look up the IP address. ## Why do I need to configure my Hosts File? When you're developing locally, you'll be using domain names like `laravel.dev.test` instead of `localhost`. This is important because it allows you to mimic real-world environments and allow you to test your application with 3rd party services. ## macOS & Linux To configure your hosts file on macOS or Linux, you'll need to edit the `/etc/hosts` file. You can do this by running the following command in your terminal: ```bash [Edit the hosts file on macOS or Linux] sudo nano /etc/hosts ``` This will open the hosts file in the nano text editor. You'll see a list of IP addresses and domain names. To add a new entry, simply add a new line at the bottom of the file with the IP address followed by the domain name. For example: ```bash [Add a new entry to the hosts file] 127.0.0.1 laravel.dev.test 127.0.0.1 mailpit.dev.test 127.0.0.1 vite.dev.test 127.0.0.1 reverb.dev.test 127.0.0.1 meilisearch.dev.test ``` Press `CTRL + O` (that's an "oh" not a zero) to save the file, then press `Enter` to confirm the filename. Press `CTRL + X` to exit nano. ::note You will also have to set the `SESSION_DOMAIN` variable within your `.env` file to what you choose for your development domain. ex: `SESSION_DOMAIN=laravel.dev.test` :: ## Windows To configure your hosts file on Windows, you'll need to edit the `C:\Windows\System32\drivers\etc\hosts` file. You can do this by editing the file in Notepad. You'll need to run Notepad as an administrator to edit the file. To do this, open up the Start menu and search for Command Prompt. Right-click on Command Prompt and select "Run as administrator". ::responsive-image --- maxWidth: 500 alt: Run Command Prompt as administrator src: https://getspin.pro/images/docs/run-cmd-admin.png --- :: Once you have a command prompt open, you can run the following command to open the hosts file in Notepad: ```bash [Edit the hosts file on Windows] notepad C:\Windows\System32\drivers\etc\hosts ``` This will open the hosts file in Notepad. You'll see a list of IP addresses and domain names. To add a new entry, simply add a new line at the bottom of the file with the IP address followed by the domain name. For example: ```bash [Add a new entry to the hosts file] 127.0.0.1 laravel.dev.test 127.0.0.1 mailpit.dev.test 127.0.0.1 vite.dev.test 127.0.0.1 reverb.dev.test 127.0.0.1 meilisearch.dev.test ``` Press `CTRL + S` to save the file, then close Notepad. ## Testing your Configuration Once you've added the entries to your hosts file, you can test by ping the domain name in your terminal or command prompt. For example: ```bash [Ping the domain name] ping laravel.dev.test ``` You should see the IP address `127.0.0.1` in the output. This means your hosts file is configured correctly. # Connecting to your database ## How databases are configured When you use Spin, databases are configured through environment variables (the `.env` file or `.env.` file). When your databases start for the first time on the your machine, it uses whatever is in the environment variable file to create the database with the correct credentials. ::note **⚠️ NOTE: If you change the credentials in your `.env` file after you've already started the database, the database will not automatically update to your new credentials.** You'll have to manually update the credentials in the database itself. Refer to the official Docker image documentation for the database you're using for more details. :: ## Connecting to a local development database We can use a GUI manager like [TablePlus](https://tableplus.com/){rel=""nofollow""} to connect to our local development database. To do so, ensure you have the `spin up` command running and then open TablePlus. When you create a connection, we can use the credentials from your `.env` file. ::responsive-image --- maxWidth: 500 alt: Connect to Postgres src: https://getspin.pro/images/docs/db-connection-postgres.png --- :: ::note In development, you want to use the host of `127.0.0.1` instead of `postgres, mysql, or mariadb`. This is because we expose the ports to your local machine in `docker-compose.dev.yml`. :: | Field | Value | | ----------- | ---------------------------------------------------------------- | | Host/Socket | `127.0.0.1` (we expose the ports to your local machine) | | Port | Value of `DB_PORT` in your `.env` file | | User | Value of `DB_USER` in your `.env` file | | Password | Value of `DB_PASSWORD` in your `.env` file | | Database | Value of `DB_DATABASE` in your `.env` file | | Over SSH | ❌ Do not use. We want a direct connection to your local machine. | ## Connecting to a production database Since exposing database ports is a security risk, we don't expose the database ports in production. Instead, you can use an SSH tunnel to connect to your database. We do this by using a secure SSH tunnel with key-based authentication with our open source image called [serversideup/docker-ssh](https://github.com/serversideup/docker-ssh){rel=""nofollow""}. ![Connect to database over SSH](https://getspin.pro/images/docs/database-connection-over-ssh.png) ### How it works In your `docker-compose.prod.yml` file, you will notice a service called `ssh` This service will: - Create a docker service called `ssh` with `serversideup/docker-ssh` - Expose a secure SSH service on port `2222` - Configure the SSH username to `tunnel` - Allow keys to connect that are set by `AUTHORIZED_KEYS` - Allow IP addresses to connect that are set by `ALLOWED_IPS` ```yaml [SSH Service Configuration by Default] ssh: # We use an SSH image so we can securely tunnel into the Docker network with # tools like Sequel Pro, TablePlus, Sequel Ace, etc. # Learn more how to secure your tunnel here: https://github.com/serversideup/docker-ssh image: serversideup/docker-ssh:v2.0.0 ports: - target: 2222 published: 2222 mode: host environment: # Be sure to set the authorized keys in the .env file or GitHub Actions secrets AUTHORIZED_KEYS: "${AUTHORIZED_KEYS}" # You can lock to a specific IP too (AllowUsers tunnel@1.2.3.4) ALLOWED_IPS: "AllowUsers tunnel" ``` ### Configure "AUTHORIZED\_KEYS" for GitHub Actions We made the process stupid simple for people using GitHub Actions. When you're going through [the process of setting up GitHub Actions](https://getspin.pro/docs/deployment/automated-deployments-with-github-actions), the `AUTHORIZED_KEYS` variable will automatically be configured by looking at your `.spin.yml` file and setting the `AUTHORIZED_KEYS` variable to any public keys set for any `sudo` users. ```bash [Configure GitHub Actions] # This automatically configures the AUTHORIZED_KEYS variable for you spin configure gha ``` If you need to update the `AUTHORIZED_KEYS` variable, you can simply update your `.spin.yml` and run the `spin configure gha` command again. You can verify the secret is set by going to Settings > Secrets > Actions > `AUTHORIZED_KEYS` in your GitHub repository. ### Configure "AUTHORIZED\_KEYS" for "spin deploy" Setting the `AUTHORIZED_KEYS` variable for "spin deploy" is just as easy as GitHub Actions. Every time you run `spin deploy`, it will automatically set and update the `.infrastructure/conf/ci/AUTHORIZED_KEYS` file, which will include any public keys from users in the `sudo` group that are set in your `.spin.yml` file. The deploy command will automatically load the contents of this file into the `AUTHORIZED_KEYS` environment variable during the deployment process. ### Locking down your SSH tunnel If you'd like to take security a step further, you can lock down the IP addresses that can connect to your SSH tunnel. This is done by setting the `ALLOWED_IPS` environment variable: ```yaml [Lock down your SSH tunnel to specific IP addresses] ssh: image: serversideup/docker-ssh:v2.0.0 ports: - target: 2222 published: 2222 mode: host environment: AUTHORIZED_KEYS: "${AUTHORIZED_KEYS}" # 👇 We lock to the specific IP address of 1.2.3.4 ALLOWED_IPS: "AllowUsers tunnel@1.2.3.4" ``` The above configuration will only allow the IP address `1.2.3.4` to connect to the SSH tunnel. If anyone tries to connect from any other IP address, they will be denied access. ### Create a connection in TablePlus You'll need to make a deployment via `spin deploy` or using GitHub Actions. You need to make sure the deployment is successful and that the SSH tunnel is running. Once that's ready, you're ready to connect TablePlus to your database. Create a new connection and click `Over SSH`. ::responsive-image --- maxWidth: 500 alt: Enable SSH in TablePlus src: https://getspin.pro/images/docs/tableplus-enable-ssh.png --- :: You'll see the menus expand out where you can add more details. ::responsive-image --- maxWidth: 500 alt: TablePlus Connection Example src: https://getspin.pro/images/docs/tableplus-connection-example.png --- :: Use the table below to help you configure your connection: ::note Notice how the database host is the service name `postgres`, `mysql`, or `mariadb`. This is because the SSH tunnel will connect to the service name in the Docker network. :: | Field | Value | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Host/Socket | `postgres`, `mysql`, or `mariadb` (it's the service name in the Docker network) | | Port | The value of `DB_PORT` in your `.env.` file | | User | The value of `DB_USER` in your `.env.` file | | Password | The value of `DB_PASSWORD` in your `.env.` file | | Server | (Your server's hostname or IP address) | | Port | `2222` (This is DIFFERENT from your regular SSH connection) | | User | `tunnel` (This is the default user for the SSH container and should be the same for all users) | | SSH Password | ⚠️ Leave this blank. | | Use SSH key | ✅ Check this box. | | Import a private key | For most people, if your private key is located in `~/.ssh` the connection should work by default. If you need to select a specific private key, then click this button to select. | Once you've filled in the details, click `Connect` and you should be able to connect to your database. ::responsive-image --- maxWidth: 500 alt: Successful Connection src: https://getspin.pro/images/docs/tableplus-successful-connection.png --- :: ### Troubleshooting your connection If you're having issues connecting to your database, try debugging your SSH connection first. ```bash [Debugging your SSH connection] # Attempt to connect to the SSH tunnel ssh -p 2222 tunnel@ ``` If you're able to connect, then you know the SSH tunnel is working. Once connected, you can run `ping ` to see if the database service is responding. ```bash [Ping the database service] # The service name could be postgres, mysql, or mariadb ping ``` If you're able to ping the service, then you know the database service is responding. The final step is to ensure your database credentials and settings are correct (double check your `.env.` file and your `.spin.yml` file). ::note **⚠️ NOTE: If you change the credentials in your `.env` file after you've already started the database, the database will not automatically update to your new credentials.** You'll have to manually update the credentials in the database itself. Refer to the official Docker image documentation for the database you're using for more details. :: # Customizing Development URLs ## How URLs are configured We use Traefik as a reverse proxy to route traffic to your containers. Traefik uses labels in your `docker-compose.*.yml` files to determine how to route traffic. There are labels that you can apply to your services to customize the URL. Here is an example of a service in your `docker-compose.dev.yml` file: ```yaml [Default URL for PHP service in docker-compose.dev.yml] services: php: labels: - "traefik.enable=true" - "traefik.http.routers.laravel-web.rule=Host(`laravel.dev.test`) || HostRegexp(`^.+\\.ngrok-free\\.app$`)" - "traefik.http.routers.laravel-web.tls=true" - "traefik.http.routers.laravel-web.entrypoints=websecure" - "traefik.http.services.laravel-web.loadbalancer.server.port=8443" - "traefik.http.services.laravel-web.loadbalancer.server.scheme=https" ``` You can see by default, we use `laravel.dev.test` as the URL, as long as supporting Ngrok's free plan by default. You can change this to any domain you'd like. ## Updating the hosts file Just remember, you'll need to [add the domain to your hosts file](https://getspin.pro/docs/advanced/configuring-your-hosts-file) to make sure your computer knows where to route the traffic. # Customizing The Docker Image ## Where your Docker image is defined You'll notice two files in your project that are used for your application: ```bash [Project Dockerfiles] . ├── Dockerfile.node # Used for Node └── Dockerfile.php # Used for PHP ``` ## Customizing the image You'll notice in the files are a `FROM` statement. These are the base images that we use for your project. You can visit each of the Docker Hub pages for that image to see full examples of how to customize the image. We also utilize [multi-stage builds]() with Docker so we can customize experiences based on the environment. For the PHP image, we use our own open-source image called [serversideup/php](https://github.com/serversideup/docker-php/){rel=""nofollow""}, which are highly optimized for Spin and Laravel projects. ## Adjusting environment variables You'll notice in the `docker-compose.*.yml` files, we pass environment variables to the image. Feel free to adjust those to your needs, especially on the `php` service. ```yaml [docker-compose.prod.yml] services: php: image: ${SPIN_IMAGE_DOCKERFILE_PHP} environment: # 👇 Set this to "false" if you want to run migrations manually AUTORUN_ENABLED: "false" APP_ENV: "${SPIN_DEPLOYMENT_ENVIRONMENT}" PHP_OPCACHE_ENABLE: "1" # 👇 Set a custom healthcheck path or delete the line if you want the default healthcheck path HEALTHCHECK_PATH: "/my-app-healthcheck" ``` To view all the customizations you can make with the serversideup/php image, see the [serversideup/php documentation](https://serversideup.net/open-source/docker-php/docs/customizing-the-image){rel=""nofollow""}. ## Installing PHP extensions The serversideup/php project comes with a lot of great documentation, specifically on [how to install additional PHP extensions](https://serversideup.net/open-source/docker-php/docs/customizing-the-image/installing-additional-php-extensions){rel=""nofollow""}. Here's an example of installing `bcmath` and `gd` PHP extensions: ```dockerfile [Dockerfile.php] ############################################ # Base Image ############################################ # 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-alpine AS base # Since the container is unprivileged by default, we need to switch to root # to install additional PHP extensions. USER root RUN install-php-extensions bcmath gd ############################################ # Development Image ############################################ FROM base AS development # We can pass USER_ID and GROUP_ID as build arguments # to ensure the www-data user has the same UID and GID # as the user running Docker. ARG USER_ID ARG GROUP_ID # Switch to root so we can set the user ID and group ID USER root # Set the user ID and group ID for www-data RUN docker-php-serversideup-set-id www-data $USER_ID:$GROUP_ID && \ docker-php-serversideup-set-file-permissions --owner $USER_ID:$GROUP_ID --service nginx # Drop privileges back to www-data USER www-data ############################################ # CI image ############################################ FROM base AS ci # Sometimes CI images need to run as root # so we set the ROOT user and configure # the PHP-FPM pool to run as www-data USER root RUN echo "user = www-data" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf && \ echo "group = www-data" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf ############################################ # Production Image ############################################ FROM base AS deploy COPY --chown=www-data:www-data . /var/www/html USER www-data ``` ## Understanding targets In the `docker-compose.dev.yml` file, you'll notice that we use the `target` argument to specify which stage of the Dockerfile to use. This will only build the image for that specific stage. ```yaml [docker-compose.dev.yml] services: php: build: target: development args: USER_ID: ${SPIN_USER_ID} GROUP_ID: ${SPIN_GROUP_ID} dockerfile: Dockerfile.php ``` The above will look for `Dockerfile.php` and build the `development` stage of the Dockerfile, while passing some environment variables to the development build stage to ensure our file permissions are correct. # Exposing Secure Tunnels ## Default configuration By default, Spin Pro supports using [Ngrok's Free Plan](https://ngrok.com/){rel=""nofollow""} to expose your services to the internet. You'll need to create an account with Ngrok and install it to your machine following their instructions. ::responsive-image --- maxWidth: 500 alt: Install Ngrok src: https://getspin.pro/images/docs/ngrok-install.png --- :: ## Using Ngrok Once Ngrok is installed and authenticated, you can start a very basic tunnel by running the following command in your terminal: ```bash [Start a tunnel] ngrok http https://localhost ``` You will need to keep the terminal window open to keep the tunnel active, but you can find your public URL in the terminal output. This URL can be shared with anyone to access your local services. If you'd like to learn about more advanced features of Ngrok, check out their [docs](https://ngrok.com/docs/http/){rel=""nofollow""}. ::responsive-image --- maxWidth: 500 alt: Ngrok connected src: https://getspin.pro/images/docs/ngrok-connected.png --- :: ## Customizing the tunnel By default, Spin Pro supports any `*.ngrok-free.app` domain that connects. If you need to change this, open up your `docker-compose.dev.yml` file and update the labels for the `php` service. ```yaml [docker-compose.dev.yml] services: php: labels: - "traefik.http.routers.laravel-web.rule=Host(`laravel.dev.test`) || HostRegexp(`^.+\\.ngrok-free\\.app$`)" ``` You can change the `^.+\\.ngrok-free\\.app$$` expression to match any domain you need to support. # Migrating from Spin v2 to v3 ::note **Spin v3 ships with zero breaking changes for Spin v2 configurations.** This means these steps are completely optional and is only required if you want to take advantage of the new features with Spin (like using native providers to provision servers on DigitalOcean, Vultr, and Hetzner) :: ## The new ".spin.yml" file In Spin v3, we introduced a new way to manage your server inventory. Previously, we had the configurations separated across multiple files (`.spin-inventory.ini` and `.spin.yml`). Everything has been merged into a single `.spin.yml` file. This new format gives you the ability to provision servers right from the command line with providers like DigitalOcean, Vultr, and Hetzner. ```yaml [Example .spin.yml with v3] ############################################################## # 👇 Users - You must set at least one user ############################################################## users: # - username: alice # name: Alice Smith # groups: ['sudo'] # authorized_keys: # - public_key: "ssh-ed25519 AAAAC3NzaC1lmyfakeublickeyMVIzwQXBzxxD9b8Erd1FKVvu alice" # - username: bob # name: Bob Smith # state: present # password: "$6$mysecretsalt$qJbapG68nyRab3gxvKWPUcs2g3t0oMHSHMnSKecYNpSi3CuZm.GbBqXO8BE6EI6P1JUefhA0qvD7b5LSh./PU1" # groups: ['sudo'] # shell: "/bin/bash" # authorized_keys: # - public_key: "ssh-ed25519 AAAAC3NzaC1anotherfakekeyIMVIzwQXBzxxD9b8Erd1FKVvu bob" ############################################################## # 👇 Providers - You must set at least one provider ############################################################## providers: # - name: digitalocean # api_token: Set token here OR delete this line and set environment variable DO_API_TOKEN # - name: hetzner # api_token: Set token here OR delete this line and set environment variable HCLOUD_TOKEN # - name: vultr # api_token: Set token here OR delete this line and set environment variable VULTR_API_KEY ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: # - server_name: ubuntu-2gb-ash-1 # environment: production # hardware_profile: hetzner_2c_2gb_ubuntu2404 # - server_name: ubuntu-1gb-ord-2 # environment: staging # hardware_profile: vultr_1c_1gb_ubuntu2404 ############################################################## # 🤖 Hardware Profiles ############################################################## hardware_profiles: # Hetzner - name: hetzner_2c_2gb_ubuntu2404 provider: hetzner profile_config: location: ash server_type: cpx11 image: ubuntu-24.04 backups: true # Vultr - name: vultr_1c_1gb_ubuntu2404 provider: vultr profile_config: region: ord plan: vc2-1c-1gb os: "Ubuntu 24.04 LTS x64" backups: true # DigitalOcean - name: digitalocean_1c_1gb_ubuntu2404 provider: digitalocean profile_config: region: nyc3 size: s-1vcpu-1gb image: ubuntu-24-04-x64 backups: true ############################################################## # 🌎 Environments ############################################################## environments: - name: production - name: staging - name: development ############################################################## # 🤓 Advanced Server Configuration ############################################################## # Timezone and contact settings server_timezone: "Etc/UTC" server_contact: changeme@example.com # If you the SSH port below, you may need to run `spin provision -p ` # to get a connection on your first provision. Otherwise, SSH will try connecting # to your new port before the SSH server configuration is updated. ssh_port: "22" ## You can set this to false to require a password for sudo. ## If you disable passwordless sudo, you must set a password for all sudo users. ## generate an encrypted hash with `spin mkpasswd`. Learn more: ## https://serversideup.net/open-source/spin/docs/command-reference/mkpasswd use_passwordless_sudo: true ## Email Notifications postfix_hostname: "{{ inventory_hostname }}" ## Set variables below to enable external SMTP relay # postfix_relayhost: "smtp.example.com" # postfix_relayhost_port: "587" # postfix_relayhost_username: "myusername" # postfix_relayhost_password: "mysupersecretpassword" ## Deploy user customization - You can customize the deploy user below if you'd like # docker_user: # username: deploy # authorized_ssh_keys: # - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKNJGtd7a4DBHsQi7HGrC5xz0eAEFHZ3Ogh3FEFI2345 fake@key" # - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFRfXxUZ8q9vHRcQZ6tLb0KwGHu8xjQHfYopZKLmnopQ anotherfake@key" ``` ## What's changed We changed a few things regarding this new set up: - The `.spin-inventory.ini` is no longer configured on new projects - The `.spin.yml` file now manages both server settings and inventory (instead of just settings before) - On project creation, the `.spin.yml` file is no longer included in the repository by default (it acts like an `.env` file) - On project creation, you are no longer prompted to encrypt your `.spin.yml` file (you can still do this manually) - `use_passwordless_sudo` is now set to `true` by default, allowing sudo users to become root without a password, but they are still authenticated by their SSH key. Keep this value to `false` if you'd like to require a password for sudo. ## How to migrate a project to the new structure You can continue to use your existing set up if you'd like, but if you want the new features, here is how you can take a Spin v2 project and set it up like a brand new Spin v3 project. ### Make a backup This is always a good idea when you're making big changes like this. It's better to have one than not 😃. Here's where you should make backups: - Make a copy of your local project directory - Take a snapshot/backup of your production and staging servers - Make sure you're on a clean branch within your project - Plan and communicate to your users that there may be a brief interruption during the upgrade (running `spin provision` might update packages and cause 1-2 minutes of downtime) ### Ensure your .gitignore is up to date Essentially what we want to do, is remove `.spin.yml` from the Git repository (unless if you find a certain use case to keep it in there -- as long as it's encrypted with a secure password). ```text [Ensure these exist in your .gitignore] .spin* .vault-password ``` ### Ensure your `.env.` files are up to date Depending how you deploy, we may be re-uploading your `.env.` files to GitHub Actions. Make sure your Laravel `.env` files are accurate to what's currently running in your environment. ### Remove the ".spin-inventory.ini" file and ".spin.yml" file from the repository We know what to remove the files from being tracked by Git. ```bash [Stop tracking these files in Git] git rm --cached .spin-inventory.ini git rm --cached .spin.yml ``` ### Decrypt your files so you can edit them To make it easy for you, it's probably easiest to decrypt your files so you can easily edit them. ```bash [Decrypt your files] spin vault decrypt .spin-inventory.ini spin vault decrypt .spin.yml ``` ### Rename your ".spin.yml" file to ".spin.original.yml" We just need to temporarily rename the file so we can reference it. ### Download the new ".spin.yml" file You can copy the contents of our example file from GitHub and paste into our new `.spin.yml` file. [View latest .spin.yml file on GitHub →](https://github.com/serversideup/ansible-collection-spin/blob/hardware-support/.spin.example.yml){rel=""nofollow""} ### Migrate contents from your ".spin.original.yml" file Move any setting you'd like, but especially do not forget about these: - `server_timezone` - `users` - `server_contact` - `use_passwordless_sudo` ### Migrate the contents of your ".spin-inventory.ini" file The other important thing is to move over our inventory from our `.spin-inventory.ini` file. To do this, let's say we have this example: ```ini [Example .spin-inventory.ini] ########################################### # 👇 Basic Server Configuration - Set your server DNS or IP address ########################################### [production_manager_servers] server01.example.com [staging_manager_servers] server02.example.com ########################################### # 🤓 Advanced Environment Settings ########################################### # Swarm Configuration [swarm_managers:children] production_manager_servers staging_manager_servers # Environment [production:children] production_manager_servers [staging:children] staging_manager_servers [all_servers:children] production staging ``` The most important thing in the file is our "Basic Server Configuration" section. You can see this file has two servers, `server01.example.com` and `server02.example.com`. We want to move them into our `.spin.yml` file, so it looks like this: ```yaml [Example .spin.yml with migrated inventory] ############################################################## # 👇 Servers - You must set at least one server ############################################################## servers: - server_name: server01.example.com # ✅ You can set this to anything you want. It's just a label. environment: production # 👇 You MUST set this. Make sure it matches from your ".spin-inventory.ini" file address: server01.example.com # ❌ You can delete the line below if you're not using our native providers # hardware_profile: hetzner_2c_2gb_ubuntu2404 # 👇 Here is a full example of "server02.example.com" without comments - server_name: server02.example.com environment: staging address: server02.example.com ``` ### Remove the "providers" and "hardware\_profiles" sections if you want If you do not want the native providers to be used, you can remove the `providers` and `hardware_profiles` sections. As long as your server has an `address` set, Spin will use whatever host you'd like. ::note Keep these sections if you want to use the native providers. :: ```yaml [❌ You can remove these lines if you want] # ############################################################## # # 👇 Providers - You must set at least one provider # ############################################################## # providers: # - name: digitalocean # api_token: Set token here OR delete this line and set environment variable DO_API_TOKEN # - name: hetzner # api_token: Set token here OR delete this line and set environment variable HCLOUD_TOKEN # - name: vultr # api_token: Set token here OR delete this line and set environment variable VULTR_API_KEY # ############################################################## # # 🤖 Hardware Profiles # ############################################################## # hardware_profiles: # # Hetzner # - name: hetzner_2c_2gb_ubuntu2404 # provider: hetzner # profile_config: # location: ash # server_type: cpx11 # image: ubuntu-24.04 # backups: true # # Vultr # - name: vultr_1c_1gb_ubuntu2404 # provider: vultr # profile_config: # region: ord # plan: vc2-1c-1gb # os: "Ubuntu 24.04 LTS x64" # backups: true # # DigitalOcean # - name: digitalocean_1c_1gb_ubuntu2404 # provider: digitalocean # profile_config: # region: nyc3 # size: s-1vcpu-1gb # image: ubuntu-24-04-x64 # backups: true ``` ### Remove the v2 configuration files Make sure to delete the old v2 files from the project when you're confident you've migrated everything. ```bash [Remove the files from the project] rm .spin-inventory.ini rm .spin.original.yml ``` ### Re-encrypt (if you want) With this new set up, the `.spin.yml` file acts like an `.env` file. If you'd like the extra security, you can re-encrypt the file. ::note If you choose TO NOT encrypt the file, be sure to delete the `.vault-password` file from your project root directory. :: ```bash [Re-encrypt the file] spin vault encrypt .spin.yml ``` You will need a `.vault-password` file on your local machine if you intend to use the encrypted file. ### Run spin provision If you'd like to test the new setup, you can run `spin provision` and it will use the new `.spin.yml` file. ::note ⚠️ Running `spin provision` might cause a brief interruption in your services if there is an update for Docker. :: ```bash [Run spin provision on your staging servers] spin provision staging ``` ### Update GitHub Actions If you're using GitHub Actions, we no longer need these environment variables. They will be reuploaded to GitHub Actions under new names when we run `spin configure gha `. | Environment Variable | New Behavior | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ENV_FILE_BASE64` | This has been renamed to `_ENV_FILE_BASE64`. It will be recreated with `spin configure gha `. | | `SSH_REMOTE_HOSTNAME` | This has been renamed to `_SSH_REMOTE_HOSTNAME`. It will be recreated with `spin configure gha `. | | `SSH_DEPLOY_PRIVATE_KEY` | You can keep this if you want. But if you do let it, we automatically create a new deploy key for you, store it under `.infrastructure/ci/SSH_DEPLOY_PRIVATE_KEY` and add it to GitHub Actions secrets. This process happens when you run `spin configure gha `. | ::note If you added other variables such as `DB_PASSWORD` or `REDIS_PASSWORD`, you can remove those from GitHub Actions if you're confident your `.env.` files are accurate. Spin v3 will use the values from your `.env.` files to configure these services. :: ### Run "spin configure gha :environment["] For each environment, you will need to run `spin configure gha ` to update the GitHub Actions environment variables. ```bash [Run "spin configure gha "] spin configure gha staging spin configure gha production ``` ### Get latest Spin template If you purchased Spin Pro, you can get the latest GitHub Actions template by reinitializing your project. ::note The command below will delete all Dockerfiles and Spin configurations then ask you to reinitialize your project. If you made a lot of customizations to the Dockerfiles and Spin templates, you way want to manually copy the GitHub Actions template over. :br:br**The links below are only accessible to Spin Pro customers.**:br - [action\_deploy-production.yml](https://github.com/serversideup/spin-template-laravel-pro/blob/main/blocks/github-actions/.github/workflows/action_deploy-production.yml){rel=""nofollow""} - [service\_docker-build-and-publish.yml](https://github.com/serversideup/spin-template-laravel-pro/blob/main/blocks/github-actions/.github/workflows/service_docker-build-and-publish.yml){rel=""nofollow""} :: ```bash [Reinitialize your project] spin init laravel-pro ``` ## Review your pending Git changes Now is the time to review your pending Git changes. If you're confident everything looks good, you can go ahead and commit your changes and run your deployment. Once the deployment is complete, you're ready for Spin v3 and all the exciting new features! 🎉 # Laravel Boost ::responsive-image --- maxWidth: 500 alt: Laravel Boost src: https://getspin.pro/images/docs/laravel-boost.png --- :: ## What is Laravel Boost? ::warning Make sure to upgrade to Spin `v3.2.0` or higher to use Laravel Boost. You can upgrade by running `spin run php composer update serversideup/spin`. :: [Laravel Boost](https://laravel.com/docs/13.x/boost){rel=""nofollow""} accelerates AI-assisted development by providing the essential guidelines and agent skills that help AI agents write high-quality Laravel applications. It includes a built-in MCP (Model Context Protocol) server that gives your AI coding agent access to your application's structure, database, routes, and all of Laravel's documentation. Because Spin runs your Laravel application inside Docker containers, the MCP server needs to run inside the container where PHP and Artisan are available. This guide walks you through configuring and installing Boost with Spin. ## How it works Laravel Boost's MCP server uses **stdio** (standard input/output) as its transport. Your AI coding tool communicates with the MCP server by sending and receiving JSON-RPC data through the process's stdin and stdout streams. Since Spin runs PHP inside Docker, we need to bridge your host machine (where the IDE runs) to the container (where PHP and Artisan live). Spin ships a lightweight bridge script called `spin-mcp-wait.sh` that handles this automatically. It: 1. Runs the MCP command inside the container using `spin run -T` (the `-T` flag disables pseudo-TTY allocation, which would interfere with the raw stdio data) 2. Filters Docker's startup noise from stdout so only clean JSON-RPC messages reach the IDE 3. Retries every few seconds until Docker is available — necessary because IDEs like Cursor start MCP servers on launch, before Docker Desktop may be ready The script is installed automatically as a binary when you install Spin via Composer or NPM — no manual setup required. ## Preparing the .env file Before installing Boost, add these values to your `.env` file so Boost generates the correct MCP configuration: ```bash [.env] BOOST_PHP_EXECUTABLE_PATH="./vendor/bin/spin-mcp-wait.sh ./vendor/bin/spin run -T php php" BOOST_COMPOSER_EXECUTABLE_PATH="./vendor/bin/spin run php composer" BOOST_NPM_EXECUTABLE_PATH="./vendor/bin/spin run node npm" ``` Why each is needed: - **`BOOST_PHP_EXECUTABLE_PATH`** — Tells Boost how to start the MCP server. Without this, Boost will try to run bare `php` on the host, which doesn't exist since PHP runs inside Docker. - **`BOOST_COMPOSER_EXECUTABLE_PATH`** — Tells Boost's AI guidelines to use `spin run php composer` instead of bare `composer` when generating instructions for AI agents. - **`BOOST_NPM_EXECUTABLE_PATH`** — Same as above, but for npm commands. ## Installation Now that the `.env` file is ready, install Laravel Boost: ```bash [Install Laravel Boost] spin run php composer require laravel/boost --dev ``` ::note Make sure it installs at least version 2.2 or higher (`"laravel/boost": "^2.2"`) :: Next, install the MCP server and coding guidelines. When prompted, select the AI agents you plan to use (Cursor, Claude Code, etc.): ```bash [Run the Boost installer] spin run php php artisan boost:install ``` The `boost:install` command generates the relevant guideline and skill files for the coding agents you selected. Feel free to add the generated configuration files to your `.gitignore` since they are automatically regenerated when running `boost:install` or `boost:update`. For example, we include this in our `.gitignore` file: ```bash [.gitignore] # Boost-generated (regenerated by boost:update) AGENTS.md CLAUDE.md boost.json .mcp.json .cursor/mcp.json .cursor/rules/laravel-boost.mdc .cursor/skills/ .agents/ .codex/ .claude/ opencode.json ``` ## Learn More Laravel Boost offers much more than what's covered here, including custom AI guidelines, agent skills, and a powerful documentation API. For the full reference, visit the [official Laravel Boost documentation](https://laravel.com/docs/13.x/boost){rel=""nofollow""}. # Laravel Horizon ## Installation To install Laravel Horizon, you will be prompted to include the Laravel Horizon service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install Laravel Horizon src: https://getspin.pro/images/docs/service-install/horizon.png --- :: ## What Spin does for you When you install Laravel Horizon, Spin will automatically choose to install Redis and set up a dedicated "Horizon" service for you. By default, the service runs the following command: ```bash [Default Command] php artisan horizon ``` ## Usage Once you run `spin up` in your local development environment, you can access the Laravel Horizon dashboard by visiting `http://laravel.dev.test/horizon`. # Laravel Octane ## What is Laravel Octane? Laravel Octane keeps your application loaded in memory between requests, dramatically reducing the overhead of bootstrapping your Laravel application on each request. This results in significantly faster response times and improved throughput. ## Installation To install Laravel Octane, you will be prompted to include the Laravel Octane service during Spin installation. Simply select it when prompted. ::note Laravel Octane in Spin Pro uses **FrankenPHP** as the application server. We do not use Swoole or RoadRunner. :: ## What Spin does for you When you install Laravel Octane, Spin automatically: - Configures your Dockerfile to support FrankenPHP - Sets up your Docker Compose configuration - Installs and configures Laravel Octane with FrankenPHP - Creates a dedicated "Octane" service that runs the following command: ```bash [Default Command] php artisan octane:start --server=frankenphp --port=8080 ``` ## Performance Benefits With Laravel Octane and FrankenPHP, your application gains: - **Memory Persistence**: Your application stays loaded in memory between requests - **HTTP/2 & HTTP/3 Support**: Modern web protocols for faster data transfer - **Automatic HTTPS**: Built-in TLS certificate management - **Worker Mode**: Handle multiple requests with a single application boot - **Reduced Latency**: Eliminate bootstrapping overhead on each request ## Usage Once you run `spin up` in your development environment, your Laravel application will be served by Octane with FrankenPHP. You can access your application at the standard URL: `http://laravel.dev.test` ::note Your application will feel noticeably faster, especially for complex applications with many service providers, middleware, or database queries during bootstrapping. :: ## Important Considerations When using Laravel Octane, keep these points in mind: - **Memory Leaks**: Be cautious of memory leaks in long-running processes - **Global State**: Avoid storing state in global variables between requests - **Singletons**: Be aware that singletons persist between requests - **File Changes**: In development, the server automatically restarts when files change ::note Always test your application thoroughly with Octane, as the persistent nature can expose issues that don't appear in traditional request/response cycles. :: # Laravel Pint ## Installation To install Laravel Pint, make sure you're familiar with the official Laravel documentation on [how to install Pint](https://laravel.com/docs/12.x/pint){rel=""nofollow""}. ```bash [Install Laravel Pint] spin run php composer require laravel/pint --dev ``` ## Usage Once you've installed Laravel Pint, you can run the following command to check your codebase for any issues: ```bash [Run Laravel Pint] spin run php ./vendor/bin/pint ``` ## Exclude Files If you run into issues with certain files (especially files in your `.infrastructure` directory), you can ignore them by adding them to the `.pint.json` file. ```json [.pint.json] { "exclude": [ ".infrastructure" ] } ``` # Laravel Queues ## Installation To install Laravel Queues, you will be prompted to include the Laravel Queues service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install Laravel Queues src: https://getspin.pro/images/docs/service-install/queues.png --- :: ## What Spin does for you When you install Laravel Queues, Spin will set up a dedicated "Queue" service for you. By default, the service runs the following command: ```bash [Default Command] php artisan queue:work --tries=3 ``` ## Usage When you run `spin up`, the queue service will automatically run. # Laravel Reverb ## Installation To install Laravel Reverb, you will be prompted to include the Laravel Reverb service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install Laravel Reverb src: https://getspin.pro/images/docs/service-install/reverb.png --- :: ## What Spin does for you When you install Laravel Reverb, Spin will set up a dedicated "Reverb" service for you. By default, the service runs the following command: ```bash [Default Command] php artisan reverb:start ``` ## Default Configuration | Property | Value | | ------------------- | ----------------------- | | **Development URL** | `wss://reverb.dev.test` | | **Protocol** | `HTTPS by default` | | **Port** | `443` | ## ⚠️ Special configuration notes ::note Laravel Reverb requires and additional DNS entry that needs to be different than your server's hostname and your application's hostname. :: When you're configuring your production environment, you will need to set up a DNS entry for your Reverb service. This DNS entry will be different than your server's hostname and your application's hostname. For example, if your server's hostname is `server01.example.com` and your application's hostname is `app.example.com`, you could set up a DNS entry for `socket.example.com`. This value should be set in your Laravel's environment file (`.env`) as `REVERB_HOST=socket.example.com`. You should also go to your DNS provider and set up an `A` record for `socket.example.com` to point to your server's IP address. ## Usage ::note Sometimes on your first run, the reverb service might start faster than we want. If your database isn't online, it might throw and error. If that is the case, press `CTRL+C` to stop the containers and run `spin up` again. :: When you run `spin up`, the Reverb service will automatically run. It will be made available at `wss://reverb.dev.test`. # Laravel Task Scheduler ## Installation To install the Laravel Task Scheduler, you will be prompted to include the Laravel Task Scheduler service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install Laravel Scheduler src: https://getspin.pro/images/docs/service-install/taskscheduling.png --- :: ## What Spin does for you When you install the Laravel Task Scheduler, Spin will set up a dedicated "Scheduler" service for you. By default, the service runs the following command: ```bash [Default Command] php artisan schedule:work ``` This will run the Laravel Task Scheduler every minute. [See the docs with serversideup/php](https://serversideup.net/open-source/docker-php/docs/laravel/laravel-task-scheduler){rel=""nofollow""} to learn more about how to customize the scheduler. ## Usage When you run `spin up`, the scheduler service will automatically run. # Laravel Schema Dump ## Prerequisites Make sure you already have a Spin Pro project with [`spin new`](https://getspin.pro/docs/getting-started/create-a-new-project) or [`spin init`](https://getspin.pro/docs/getting-started/add-to-an-existing-project). ## Background When we look at Laravel's documentation on [`php artisan schema:dump`](https://laravel.com/docs/12.x/migrations#squashing-migrations){rel=""nofollow""}, you can see there is discussion about how a database command-line client needs to be installed. These tools are not installed by default in serversideup/php (the base PHP image we use for Spin Pro) to minimize container size and reduce the security surface area. Adding the command-line client can add a lot of weight to your image, so only use this process if you absolutely need it. You can learn more about the default configurations of the base PHP image below: [Learn more about serversideup/php's default configurations →](https://serversideup.net/open-source/docker-php/docs/getting-started/default-configurations){rel=""nofollow""} ## Installation To add the command-line client to your Spin Pro project, we will need to add a line to the `Dockerfile.php` file. ```dockerfile [Dockerfile.php] ############################################ # Base Image ############################################ FROM serversideup/php:8.4-fpm-nginx-alpine AS base ############################################ # Development Image ############################################ FROM base AS development ... ``` Looking at the file above, we can see Spin Pro is utilizing [Docker Multi-Stage Builds](https://docs.docker.com/build/building/multi-stage/){rel=""nofollow""} to build your application image. This means you can choose where you want to install the command-line client. In most cases, you'll want this for ALL targets of your image, but it is possibly to place this command under a specific target (like `development` if needed) if you need to. In this example, we'll add it to the `base` target so this client is available for all targets. ```dockerfile [Dockerfile.php (updated with command-line client)] ############################################ # Base Image ############################################ FROM serversideup/php:8.4-fpm-nginx-alpine AS base # Install the command-line client USER root # Switch to root to install the client RUN docker-php-serversideup-dep-install-alpine mysql-client USER www-data # Switch back to the www-data user ############################################ # Development Image ############################################ FROM base AS development ... ``` You can see we add `RUN docker-php-serversideup-dep-install-alpine mysql-client` after the first `FROM` statement. We call `USER root` to switch to the root user to install the client, then call `USER www-data` to switch back to the www-data user. The `docker-php-serversideup-dep-install-*` command is made available by [serversideup/php](https://serversideup.net/open-source/docker-php/docs/reference/command-reference){rel=""nofollow""} and is used to install the command-line client for the given database. These commands are short cuts for updating the package list, installing the package, then cleaning up after the installation. You can also use `apk` or `apt-get` directly if you prefer. Just make sure you're using the correct installation command for `-alpine` or `-debian`. ### Choosing the correct client ::note You must use the client that matches your database. For example, if you are using MySQL, you must use the MySQL client. If you are using PostgreSQL, you must use the PostgreSQL client. You must also ensure the client package name is correct (Debian vs Alpine). :: ```dockerfile [Example installation commands] ############################################ # Alpine ############################################ # SQLite RUN docker-php-serversideup-dep-install-alpine sqlite # MySQL RUN docker-php-serversideup-dep-install-alpine mysql-client # MariaDB RUN docker-php-serversideup-dep-install-alpine mariadb-client # PostgreSQL RUN docker-php-serversideup-dep-install-alpine postgresql-client ############################################ # Debian ############################################ # SQLite RUN docker-php-serversideup-dep-install-debian sqlite3 # MySQL RUN docker-php-serversideup-dep-install-debian mysql-client # MariaDB RUN docker-php-serversideup-dep-install-debian mariadb-client # PostgreSQL RUN docker-php-serversideup-dep-install-debian postgresql-client ``` ## Testing your changes Once you have these lines added, you can run a `spin up --build` to test your changes and make sure the command-line client is installed and functioning as expected. Use [`spin exec`](https://getspin.pro/docs/command-reference/exec) to run commands in your container once your container is running. # Mailpit ## Installation ::note Mailpit is installed locally in **development only** by default. :: To access Mailpit, you can use the following URL: ```bash [Mailpit URL] https://mailpit.dev.test/ ``` ::responsive-image --- maxWidth: 500 alt: Mailpit UI src: https://getspin.pro/images/docs/mailpit-ui.png --- :: ## Important notes - Mailpit is only available in **development** mode. - Be sure to [configure your hosts file](https://getspin.pro/docs/advanced/configuring-your-hosts-file) to support `mailpit.dev.test` so that you can access the Mailpit UI. - If you run `spin up` and see a 404 immediately after bringing the services up, wait at least 15 seconds and try again. The mailpit container needs time to start up. ## Configuration To use Mailpit with Laravel, you need to ensure your `.env` file has the following configuration: ```bash [.env Configuration] MAIL_MAILER=smtp # For Laravel 11+ MAIL_DRIVER=smtp # For Laravel 10↓ MAIL_HOST=mailpit MAIL_PORT=1025 MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION= ``` # MariaDB ## Installation To install MariaDB, you will be prompted to include the MariaDB service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install MariaDB src: https://getspin.pro/images/docs/service-install/mariadb.png --- :: ## What Spin does for you When you install MariaDB, Spin will set up a dedicated "MariaDB" service for you with persistent volumes so you do not lose data when updating your container. ### Default Configuration The database uses the official MariaDB image. The default configuration allows us to: - ✅ Quickly set up a database service with the exact version of our choice - ✅ Automatically create databases, users, and passwords (defined by the `environment:` variables in the `docker-compose.*.yml` files) ### ⚠️ Special Connection Notes Since the database is running in a container, you will need to connect to the database using the container name. For example, if you have a Laravel application, you would use the following in your `.env` file: ::note Avoid special characters in database passwords as they can cause connection issues. Use long (20+ characters) alphanumeric passwords instead. [Generate secure passwords →](https://www.random.org/strings/?num=1&len=24&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""} :: ```bash [Example .env File] DB_CONNECTION=mysql DB_HOST=mariadb DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laraveluser DB_PASSWORD=laravelpassword ``` From your development workstation, we expose the database service on port `3306`. This is the default port for MySQL and MariaDB. This means you can use `localhost` and `3306` to connect to the database. ## Usage When you run `spin up`, the MariaDB container will create our database and start the MariaDB service. # Meilisearch ## Installation To install Meilisearch, you will be prompted to include the Meilisearch service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install Meilisearch src: https://getspin.pro/images/docs/service-install/meilisearch.png --- :: ## What Spin does for you When you select Meilisearch to be installed, Spin will: - Configure the Meilisearch docker service for development and production - Sets a default Meilisearch key for local development in your `.env` file (`developmentkey1234567890`) - Ensure Laravel Scout is installed and configured to use Meilisearch - Ensure the configuration is published to your project ## Getting access to the Meilisearch UI In development, if you've configured your hosts file correctly, you can access the Meilisearch UI at {rel=""nofollow""}. ::responsive-image --- maxWidth: 500 alt: Meilisearch UI src: https://getspin.pro/images/docs/service-install/meilisearch-ui.png --- :: ### Running the Meilisearch UI in production In general, **we do not recommend running the Meilisearch UI in production** because if it's not properly secured, it could be a security risk. If you truly need to run the Meilisearch UI in production for debugging or some other reason, you can copy the Traefik labels to `docker-compose.prod.yml` and you should also consider [protecting the Meilisearch UI with a password with Traefik](https://doc.traefik.io/traefik/middlewares/http/basicauth/){rel=""nofollow""}. ### ⚠️ Setting credentials When you configure your `.env.production` file, you will need to set the `MEILISEARCH_KEY` variable. This is the key that will be used to authenticate with Meilisearch. ::note Avoid special characters in Meilisearch keys as they can cause connection issues. Use long (20+ characters) alphanumeric keys instead. [Generate secure passwords →](https://www.random.org/strings/?num=1&len=24&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""} :: ```bash [Example .env File] SCOUT_DRIVER=meilisearch MEILISEARCH_HOST=http://meilisearch:7700 MEILISEARCH_KEY=mysupersecretkeyel6JUsBK1xbWzNPxeLeXSnxJ ``` Notice we are using `meilisearch:7700` as the host. This is because we are using the default port for Meilisearch and the service name of the Meilisearch container is `meilisearch`. ## Usage When you run `spin up`, the Meilisearch container will start automatically using the configuration details from your `.env` file. # MySQL ## Installation To install MySQL, you will be prompted to include the MySQL service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install MySQL src: https://getspin.pro/images/docs/service-install/mysql.png --- :: ## What Spin does for you When you install MySQL, Spin will set up a dedicated "MySQL" service for you with persistent volumes so you do not lose data when updating your container. ### Default Configuration The database uses the official MySQL image. The default configuration allows us to: - ✅ Quickly set up a database service with the exact version of our choice - ✅ Automatically create databases, users, and passwords (defined by the `environment:` variables in the `docker-compose.*.yml` files) ### ⚠️ Special Connection Notes Since the database is running in a container, you will need to connect to the database using the container name. For example, if you have a Laravel application, you would use the following in your `.env` file: ::note Avoid special characters in database passwords as they can cause connection issues. Use long (20+ characters) alphanumeric passwords instead. [Generate secure passwords →](https://www.random.org/strings/?num=1&len=24&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""} :: ```bash [Example .env File] DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laraveluser DB_PASSWORD=laravelpassword ``` From your development workstation, we expose the database service on port `3306`. This is the default port for MySQL and MariaDB. This means you can use `localhost` and `3306` to connect to the database. ## Usage When you run `spin up`, the MySQL container will create our database and start the MySQL service. # PostgreSQL ## Installation To install PostgresSQL, you will be prompted to include the PostgresSQL service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install PostgresSQL src: https://getspin.pro/images/docs/service-install/postgres.png --- :: ## What Spin does for you When you install PostgreSQL, Spin will set up a dedicated "PostgreSQL" service for you with persistent volumes so you do not lose data when updating your container. ### Default Configuration The database uses the official PostgreSQL image. The default configuration allows us to: - ✅ Quickly set up a database service with the exact version of our choice - ✅ Automatically create databases, users, and passwords (defined by the `environment:` variables in the `docker-compose.*.yml` files) ### ⚠️ Special Connection Notes Since the database is running in a container, you will need to connect to the database using the container name. For example, if you have a Laravel application, you would use the following in your `.env` file: ::note Avoid special characters in database passwords as they can cause connection issues. Use long (20+ characters) alphanumeric passwords instead. [Generate secure passwords →](https://www.random.org/strings/?num=1&len=24&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""} :: ```bash [Example .env File] DB_CONNECTION=pgsql DB_HOST=postgres DB_PORT=5432 DB_DATABASE=laravel DB_USERNAME=laraveluser DB_PASSWORD=laravelpassword ``` From your development workstation, we expose the database service on port `5432`. This is the default port for PostgreSQL. This means you can use `localhost` and `5432` to connect to the database. ## Usage When you run `spin up`, the PostgreSQL container will create our database and start the PostgreSQL service. # Redis ## Installation To install Redis, you will be prompted to include the Redis service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install Redis src: https://getspin.pro/images/docs/service-install/redis.png --- :: ## What Spin does for you ::note If you select to install Laravel Horizon, Spin will automatically install Redis for you. :: When you install Redis, Spin will set up a dedicated "Redis" service for you with persistent volumes so you do not lose data when updating your container. ### Default Configuration The database uses the official Redis image. The default configuration allows us to: - ✅ Quickly set up a database service with the exact version of our choice - ✅ Automatically create databases, users, and passwords (defined by the `environment:` variables in the `docker-compose.*.yml` files) ### ⚠️ Special Connection Notes Since the database is running in a container, you will need to connect to the database using the container name. For example, if you have a Laravel application, you would use the following in your `.env` file: ::note Avoid special characters in database passwords as they can cause connection issues. Use long (20+ characters) alphanumeric passwords instead. [Generate secure passwords →](https://www.random.org/strings/?num=1&len=24&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new){rel=""nofollow""} :: ```bash [Example .env File] REDIS_HOST=redis REDIS_PASSWORD=redispassword ``` ## Usage When you run `spin up`, the Redis container will create our database and start the Redis service. # SQLite ## Installation To use SQLite, you will be prompted to include the SQLite service on install. You simply just need to select it. ::responsive-image --- maxWidth: 500 alt: Install SQLite src: https://getspin.pro/images/docs/service-install/sqlite.png --- :: ## What Spin does for you When you install SQLite, Spin will automatically configure the database for you and ensure there are volume mounts for the database files so your data won't be lost when your container updates. ::note Due to Laravel's default storage method of putting the database in `database/database.sqlite`, we have to move the database to `.infrastructure/volume_data/sqlite` so we can mount the database to a directory without overwriting other Laravel files. :: Spin will automatically configure your `.env` file to do this for you: ```bash [.env] DB_CONNECTION=sqlite DB_DATABASE=/var/www/html/.infrastructure/volume_data/sqlite/database.sqlite ``` Notice how the path is prefixed with `/var/www/html`. This is because the database is mounted to the `/var/www/html` directory in the container. It is important that we reference this from the container's perspective and not your workstation's perspective. ## Usage When you run `spin up`, Laravel will be configured to use SQLite as the database. You can now run your migrations and seed your database as you normally would. # Vite ## Installation By default Spin Pro comes with Vite pre-installed. ## Default Configuration | Property | Value | | ------------------- | ----------------------- | | **Development URL** | `https://vite.dev.test` | | **Protocol** | `HTTPS by default` | | **Port** | `443` | If for some reason your vite.config.js file is heavily modified or changed by another process, here is the default configuration that Spin Pro comes with: ```js [vite.config.js] import fs from 'fs'; import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; export default defineConfig({ server: { host: '0.0.0.0', hmr: { host: 'vite.dev.test', clientPort: 443, }, https: { key: fs.readFileSync('/usr/src/app/.infrastructure/conf/traefik/dev/certificates/local-dev-key.pem'), cert: fs.readFileSync('/usr/src/app/.infrastructure/conf/traefik/dev/certificates/local-dev.pem'), }, }, plugins: [ laravel({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true, }), ], }); ``` ## Usage To use Vite, you can run the following command from your development environment: ```bash [Run Vite] spin run node yarn dev ``` ## Getting Vite Assets to Load Over HTTPS in Production In Laravel 11, you will need to force the compiled Vite assets to load over HTTPS. To do that, open the `app/Providers/AppServiceProvider.php` file and update the `boot()` method: ::note In order for the following code to take effect, the `APP_ENV` environment variable must be set to `production` or `dev`. :: ```php [app/Providers/AppServiceProvider.php] /** * Register any application services. */ public function register(): void { if ($this->app->environment('production') || $this->app->environment('dev')) { URL::forceScheme('https'); } } ``` # Getting Started Thanks for purchasing the Spin Pro template for Laravel! This guide will help you get started. :video{autoPlay="true" loop="true" muted="true" playsInline="true"} ## What you get Your purchase grants you access to a collection of Docker components that help configure your Laravel project in seconds. This is a private template stored in GitHub that integrate with your CLI to provide a beautiful onboarding experience. You can create projects with a simple command of `spin new laravel-pro`. Using these templates is an easy way to take advantage of these features: - **PAY ONCE infrastructure management**. No monthly fees (bring your own servers) - **Unlimited projects** with a any license - **Unlimited servers** with a any license - **Beautiful DX** with an easy project creation wizard - **Zero-downtime deployments** with Docker Swarm + Traefik - **Automated deployments** with GitHub Actions - **Free SSL certificate** powered by Let's Encrypt - **Deploy to any host** that runs Ubuntu 22.04+ - **Lightning-fast development** with automatically configured Vite - **Trusted SSL** for Development - **Run powerful services** like Horizon, Reverb, Redis, MySQL, Postgres, & more # Affiliates :affiliate-hero :affiliate-explanation :affiliate-apply :affiliate-ready :affiliate-faq # Managed Hosting :hosting-form :hosting-faqs