Remote dev environments that feel local. Powered by Fly.io.
Installing tons of development stuff onto your workstation sucks. Let's not but say we did.
This project:
- Creates an app on Fly.io that has your dependencies in it.
- Syncs your local code into the app on-the-fly
- Forwards defined ports (e.g. open
localhost:8000
in your browser)
The Fly app turns off automatically when you disconnect from it, so it's not running 24/7.
It'll turn back on automatically when you re-connect.
Here's how to install and use Vessel.
First, install dependencies:
- Install
flyctl
and create a Fly account viafly auth signup
- Install
vessel
For Mac/Linux, you can install vessel
this way:
# 👉 Don't forget to follow instructions to add ~/.vessel/bin to your $PATH
curl https://vessel.fly.dev/install.sh | sh
Then authenticate Vessel
# If you already logged in with `fly auth login`
vessel auth
# Else, if you have a Fly API token
vessel auth -t YOUR_TOKEN_HERE
This gives Vessel access to the Fly API token that you'd like to use. If the API token is specific to your default organization, we'll use that. Otherwise, we'll prompt to ask which organization to use. Each Fly.io organization is billed separately.
Head to a code base and run initialize your project.
# Probably a Laravel project
cd ~/Code/some-laravel-project
vessel init
Once that's finished, run the start
command to enable file syncing / port forwarding.
# Start syncing/port forwarding
vessel start
# `start` is a long-running command. You can run it in the background if you want:
vessel start -d
# Run some commands to get dependencies in your server
## (Dependencies aren't synced)
## You can also run `vessel cmd <some command here>`
vessel -- composer install
vessel -- "npm install && npm run build"
# Open http://localhost:8000 in your browser
vessel open
# Use this when syncing in the background:
vessel stop
You can run one-off commands and SSH into your environments.
Note
File syncing (and port forwarding) is done via mutagen, which also works over SSH.
Vessel supports one-off commands two ways:
vessel -- composer install
- This will runcomposer install
after connecting to your dev envvessel cmd npm install
- Similarly, This will runnpm install
after connecting to the dev env
Commands are run from the ~/app
directory within the dev environment. If you run a one-off command without first syncing, you may get
errors about the ~/app
working directory not existing.
This project configures an easy way to SSH into the dev environment.
After you run vessel init
, check your ~/.ssh/config
file to see a new entry created there. You should be able to SSH to the server without the vessel
command:
# SSH via vessel
vessel ssh
# SSH outside of Vessel
# This will match a host set in ~/.ssh/config
ssh vessel-<my-project-name> # e.g. `ssh vessel-my-app`
The vessel init
command asks what Docker base image you want to use. Fly.io takes a Docker image and transforms it into a real VM.
Vessel provides a few base images for PHP, but you are free to create your own by extending the vesselapp/base:latest
base image (which is an Ubuntu 20:04 image).
For now, you can create a container image and publish it to Docker Hub as a public image.
Then, during the vessel init
steps, you can choose Other for the Docker image and define your custom image e.g. some-username/some-image:tag
.
Private image support should be possible to support. See #11.
Your project will contain a vessel.yml
file. You can customize configuration there!
By default, Vessel will forward localhost:8000
to port 80
in the development environment, allowing you to view your application without exposing it to the world.
You can forward additional local ports to other remote ports by adding to the forwarding
list:
# Add to this list to forward additional ports
forwarding:
- 8000:80
You can adjust what files/directories get ignored (don't get synced to the remote server) as well:
# Add or remove from this list
# See https://mutagen.io/documentation/synchronization/ignores for details
ignore:
- node_modules
- vendor
Note
Vessel ignores your .git directory in all cases via Mutagen's
--ignore-vcs
flag.
You'll find global configuration and a debug log file in ~/.vessel
:
~/.vessel/config.yml
- Configuration including your Fly API token and the Fly organization used~/.vessel/debug.log
- Logs to help troubleshoot issues~/.vessel/envs/<your-project>
- A directory containing SSH keys used to access your dev environment
You can delete any app within Fly.io directly, but Vessel provides a command to cleanup local files and destroy the VM.
# Destroy the Fly VM and local files
vessel destroy
# Destroy only local files, this is handy if
# you deleted the app in Fly.io's dashboard
vessel destroy --files-only
Try adding the -v
flag to any vessel
command to get complete errors output directly to your console, e.g. vessel -v init
.
Additionally, use LOG_LEVEL=debug vessel ...
to get a bit more information output to your ~/.vessel/debug.log
file.
I haven't had a chance to test this on Windows.
Theoretically I've made the code work for Windows, but there's testing and setup to be done (based on Mutagen's requirements).
The environments will shut down after 5 minutes of inactivity. An environment is "inactive" when there are no active SSH connections (file syncing via vessel start
counts as an active SSH session).
The good news is that you won't be charged for usage when environments are not in use. However, the environments are ephemeral. When you start an environment back up,
it's as if you're starting from a blank slate. Your files will get re-synced when you run vessel start
next, but you'll need to ensure any data you need
is put back into place (for now!).
I use sqlite
for all development in this fashion (for as long as I can get away with it!), as it lets me easily have my "state" synced to the dev environment.
During the init
step, we run flyctl machine api-proxy
in the background. This proxies requests from localhost:4280
to _api.internal:4280
.
This _api.internal
address is actually a private network address that works from within Fly.io's private networks.
The other way to talk to Fly.io's Machines API is to log into your organizations private network via VPN. Instructions on setting up Fly.io's Private Networt VPN are found here.
If you use that method instead, you can:
- Talk to your VM's directly via
*.internal
hostnames - Use
vessel
by setting theFLY_HOST
environment variable
export FLY_HOST="_api.internal"
vessel init
This is the result of some fun I had using Fly's Machines API to make remote development environment.
It's inspired by:
- Me having a new computer and not wanting to install so much crap into it
- Amos's article on remote dev on Fly (This project is a bit different, but I totally stole his Rust code)