{"id":13580331,"url":"https://github.com/mardix/sailor","last_synced_at":"2025-04-07T10:29:35.190Z","repository":{"id":43037686,"uuid":"225541618","full_name":"mardix/sailor","owner":"mardix","description":"Sailor is a tiny PaaS to install on your servers/VPS that uses git push to deploy micro-apps, micro-services, sites with SSL, on your own servers or VPS","archived":false,"fork":false,"pushed_at":"2023-12-03T19:22:13.000Z","size":416,"stargazers_count":292,"open_issues_count":2,"forks_count":14,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-31T09:05:19.370Z","etag":null,"topics":["deploy","deployment","digital-ocean","digitalocean","docker","dokku","heroku","linode","microservice","nginx","paas","python","scale","single-vps","vps","worker"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mardix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-03T05:52:26.000Z","updated_at":"2025-02-27T15:18:40.000Z","dependencies_parsed_at":"2024-08-01T15:33:18.752Z","dependency_job_id":"77b756fc-3ee1-44b6-b4cf-8b4143a03fd3","html_url":"https://github.com/mardix/sailor","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mardix%2Fsailor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mardix%2Fsailor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mardix%2Fsailor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mardix%2Fsailor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mardix","download_url":"https://codeload.github.com/mardix/sailor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247635365,"owners_count":20970723,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deploy","deployment","digital-ocean","digitalocean","docker","dokku","heroku","linode","microservice","nginx","paas","python","scale","single-vps","vps","worker"],"created_at":"2024-08-01T15:01:49.907Z","updated_at":"2025-04-07T10:29:35.171Z","avatar_url":"https://github.com/mardix.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"\n# :+: Sailor :+:\n\n\u003cimg src=\"./sailor.jpeg\" style=\"width: 700px; height: auto;\"\u003e\n\n---\n## About\n\n **Sailor** is a tiny **PaaS** to install on your servers/VPS (DigitalOcean, Hetzner, Linode).\n \n It uses `git push` to deploy micro-apps, micro-services and sites.\n \nIt natively supports Python, Nodejs, Static sites, and any other languages that can use the command line. \n\nSites deployed with **Sailor** automatically have SSL assigned with LetsEncrypt.\n\n**Sailor** can run long-running background workers and cron jobs. \n\nIt allows you to deploy multiple sites/apps using a single repository. \n\nIt gives you the option of having testing/staging/production environment deployed from the same codebase.\n\n**Sailor** let's you see some stats about your apps, along with scaling them.\n\n**Sailor** makes deploying apps a smooth sailing.\n\n*Ship it like a **Sailor**!*\n\n---\n\n## Features\n\n- Automatic HTTPS\n- Git Push deployment\n- Deploy multiple apps on a single server / VPS\n- Deploy multiple apps from a single repository\n- Runs long running apps\n- Runs workers/background applications\n- Easy configuration with sailor.yml manifest\n- Easy command line setup\n- Cron-like/Scheduled script executions\n- App management: `ls, start, stop, reload, rm, stop, scale, log, info` etc\n- Run scripts during application lifecycle: `release, predeploy, postdeploy, destroy`\n- SSL/HTTPS with LetsEncrypt and ZeroSSL\n- Supports any Shell script, therefore any other languages are supported\n- Metrics to see app's health\n- Create static sites\n- Multi languages: Python, Nodejs, PHP, HTML/Static\n- Support Flask, Django, Express, etc...\n- Python \u003e= 3.8\n- Nginx\n- Logs\n\n---\n\n## + Getting Started\n\n\n#### 1. Server Requirements\n\n- Fresh server (highly recommended)\n- SSH to server with root access\n- Ubuntu 22.04\n\n\n#### 2. Install Sailor on the server\n\nOn the server, run the code below to setup the environment for Sailor and install all its dependencies. A new user, **`sailor`**, will be created and will be used to interact with SSH for Sailor.\n\n```sh\ncurl https://raw.githubusercontent.com/mardix/sailor/master/install.sh \u003e install.sh\nchmod 755 install.sh\n./install.sh\n```\n\n#### 3. Setup  Git on local repo\n\nOn your local machine, point a Git remote to your Sailor server (set in step 2), with **`sailor`** as username.\n\nFormat: `git remote add sailor sailor@$host:$app_name`\n\nWith:\n\n- `$host` The server name or IP address \n- `$app_name` The name of the application, that is set in the `sailor.yml` (the manifest to deploy)\n\nExample: `git remote add sailor sailor@my-server-host.com:myappname.com`\n\n---\n\n### + Getting work done!\n\n##### 1. Work on your app...\n\n...go into your repo and do what you do best, like a *sailor*!\n\n\n##### 2. Edit Sailor.yml\n\nAt the root of your app directory, create  `sailor.yml` (required).\n\n```\n# sailor.yml\n\n---\napps:\n    # -\u003e  with remote: sailor@$host:myapp.com\n  - name: myapp.com\n    runtime: python\n    process:\n    \n      web: \n        cmd: app:app\n        server_name: myapp.com\n        workers: 2\n        \n      cron: \"0 0 * * * python backup.py\"\n      \n      myownworker: python events-listener.py\n\n```\n\n##### 3. Add Git Remote\n\nExample: `git remote add sailor sailor@$host:myapp.com`\n\n##### 4. Deploy\n\nPush your code: ` git push sailor master`\n\n##### 5. Profit!\n\nWe did it, *Okurrr!*\n\n---\n\n### + Sailor Commands\n\nSailor communicates with your server via SSH, with the user name: **`sailor`**\n\nYou must already already have SSH access to the machine for it to work.\n\nie: `ssh sailor@$host`\n\n\n##### List all commands\n\n```\nssh sailor@$host\n```\n\n\n##### List all apps: `ls`\n\n```\nssh sailor@$host ls\n```\n\nThe command above will show the minimal info. To expand:\n\n```\nssh sailor@$host ls x\n```\n\n##### Start app: `start $app_name`\n\n\n```\nssh sailor@$host start $app_name\n```\n\n\n##### Stop app: `stop $app_name`\n\n```\nssh sailor@$host stop $app_name\n```\n\n\n##### Remove app: `rm $app_name`\n\nTo completely delete the application\n\n```\nssh sailor@$host rm $app_name\n```\n\nTo force remove an app without prompt `rm -f $app_name` \n\n```\nssh sailor@$host rm -f $app_name\n```\n\n\n##### Reload app: `reload $app_name`\n\n\nTo reload a running application\n\n```\nssh sailor@$host reload $app_name\n```\n\n\n##### Show app info: `info $app_name`\n\n```\nssh sailor@$host info $app_name\n```\n\n##### Show app log: `log $app_name`\n\n```\nssh sailor@$host log $app_name\n```\n\n\n##### Reset SSL: `reset-ssl $app_name`\n\nTo re-issue the SSL\n\n```\nssh sailor@$host reset-ssl $app_name\n```\n\n\n\n##### Scale app's workers\n\nTo increase/decrease the total workers for this process\n\n```\nssh sailor@$host scale $app_name $proc=$count $proc2=$count2\n```\n\nExample: \n\n```\nssh sailor@$host scale site.com web=4\n```\n\n##### Reload all apps: `reload-all`\n\n\n```\nssh sailor@$host apps:reload-all\n```\n\n##### Stop all apps: `stop-all`\n\n```\nssh sailor@$host apps:stop-all\n```\n\n#### -- Misc --\n\n\n##### Show the version: `x:version`\n\n```\nssh sailor@$host system:version\n```\n\n##### Update the system `x:update`\n\nTo update Sailor to the latest from Github\n\n```\nssh sailor@$host system:update\n```\n\nAdditionally, you can update from a specific branch, usually for testing purposes\n\n```\nssh sailor@$host system:update $branch-name\n```\n\n---\n\n## About\n\n**Sailor** is a utility to install on a host machine, that allows you to deploy multiple apps, micro-services, webites, run scripts and background workers on a single VPS (Digital Ocean, Linode, Hetzner).\n\n**Sailor** follows a process similar to Heroku or Dokku where you Git push code to the host and **Sailor** will:\n\n- create an instance on the host machine\n- deploy the new code\n- create virtual environments for your application\n- get a free SSL from LetsEncrypt and assign it to your domain\n- execute scripts to be executed\n- put your application online\n- monitor the application\n- restart the application if it crashes\n\n**Sailor** supports deployment for:\n\n- Python (Flask/Django)\n- Nodejs (Express)\n- PHP\n- HTML (React/Vuejs/Static).\n- any of shell scripts\n\n---\n\n### Why Sailor?\n\nSailor is a simpler alternative to Docker containers or Dokku. It mainly deals with your application deployment, similar to Heroku. \n\nSailor takes away all the complexity of Docker Containers or Dokku and gives you something simpler to deploy your applications, similar to Heroku, along with SSL.\n\n\n---\n\n### Languages Supported\n\n- Python \n- Nodejs\n- Static HTML\n- PHP\n- Any shell script\n\n---\n\n## Using `Sailor`\n\n**Sailor** supports a Heroku-like workflow, like so:\n\n* Create a `git` SSH remote pointing to your **Sailor** server with the app name as repo name.\n  `git remote add sailor sailor@[yourserver]:[appname]`.\n* Push your code: `git push sailor master`.\n* **Sailor** determines the runtime and installs the dependencies for your app (building whatever's required).\n   * For Python, it installs and segregates each app's dependencies from `requirements.txt` into a `virtualenv`.\n   * For Node, it installs whatever is in `package.json` into `node_modules`.\n* It then looks at `sailor.yml` and starts the relevant applications using a generic process manager.\n* You can optionally also specify a `release` worker which is run once when the app is deployed.\n* A `static` worker type, with the root path as the argument, can be used to deploy a gh-pages style static site.\n\n---\n\n## sailor.yml\n\n\n`sailor.yml` is a manifest format for describing apps. It declares environment variables, scripts, and other information required to run an app on your server. This document describes the schema in detail.\n\n\n`sailor.yml` contains an array of all apps to be deploy, and they are identified by `name`.\n\nWhen setting up the remote, the `name` must match the `name` in the sailor.yml\n\n\n```yml\n\n# ~ Sailor ~\n# sailor.yml\n# Sailor Configuration (https://mardix.github.io/sailor)\n#\n---\n\n# *required: list/array of all applications to run \napps:\n  - \n    # *required - the name of the application\n    name: \n    \n    # runtime: python|node|static|shell\n    # python for wsgi application (default python)\n    # node: for node application, where the command should be ie: 'node inde.js 2\u003e\u00261 | cat'\n    # static: for HTML/Static page and PHP\n    # shell: for any script that can be executed via the shell script, ie: command 2\u003e\u00261 | cat\n    runtime: static\n\n    # auto_restart (bool): to force server restarts when deploying\n    auto_restart: true\n\n    # static_paths (array): specify list of static path to expose, [/url:path, ...]\n    static_paths: \n    \n    # SSL issuer: letsencrypt(default)|zerossl\n    ssl_issuer: letsencrypt\n    \n    # threads (int): The total threads to use\n    threads: 4\n\n    # wsgi (bool): if runtime is python by default it will use wsgi, if false it will fallback to the command provided\n    wsgi: true\n\n    # nginx (object): nginx specific config. can be omitted\n    nginx:\n      include_file: ''\n    \n    # uwsgi (object): uwsgi specific config. can be omitted\n    uwsgi:\n      gevent: false\n      asyncio: false\n\n    # env (object) custom environment variable\n    env: \n      KEY: VALUE\n      KEY2: VALUE2\n\n    # scripts to run during application lifecycle\n    scripts:\n\n      # release (array): commands to execute each time the application is released/pushed\n      release: \n\n      # destroy (array): commands to execute when the application is being deleted\n      destroy: \n\n      # predeploy (array): commands to execute before spinning the app\n      predeploy:\n\n      # postdeploy (array): commands to execute after spinning the app\n      postdeploy: \n\n    # *required - process - list of all processes to run. \n    # 'web' is special, it’s the only process type that can receive external HTTP traffic \n    # only one web proctype can exist \n    # all other process name will be regular worker. \n    # The name doesn't matter \n    process:\n      # == web\n      # (dict/object): it’s the only process type that can receive external HTTP traffic\n      web: \n\n        # == (required) cmd(str) - the command to execute\n        #-\u003e cmd: app:app (for python using wsgi)\n        #-\u003e cmd: node server.js 2\u003e\u00261 cat (For other web app which requires a server command)\n        #-\u003e cmd: /web-root-dir-name (for static html+php)\n        cmd: \n        \n        # == (required) server_name(str)\n        # the server name without http/https\n        server_name: \n\n        # == server_port(str)\n        # to use IP/PORT based instead of server_name. To give access to http://IP:8080\n        # ie: \n        # server_name: _  # server_name must be set to '_'\n        # server_port: 8080\n        server_port: \n\n        # === workers(int)\n        # the number of workers to run, by default 1\n        workers: 1\n\n        # === enabled(bool)\n        # a boolean to enable/disable this process, by default true\n        enabled: true\n\n      # ==\n      # other processes (string): command to run, with a name. The name doesn't matter - It can be named anything\n      worker1: \n\n        # == (required) cmd(str) - the command to execute\n        cmd:\n\n        # === workers(int)\n        # the number of workers to run, by default 1\n        workers: 1\n\n        # === enabled(bool)\n        # a boolean to enable/disable this process, by default true\n        enabled: true\n            \n      \n      # == \n      # for simplicity you can pass the command in the name as a string\n      # workerX: python script.py\n      workerX: \n      \n      # == cron\n      # Cron proc allows you to run script periodically like cronjob\n      # similar to web, only one cron can exist. And it can only have 1 worker\n      # Also, put the cron in quotes to prevent deploy error\n      # Simple cron expression: \n      # minute [0-59], hour [0-23], day [0-31], month [1-12], weekday [1-7] (starting Monday, no ranges allowed on any field)\n      # cron: \"* * * * * python cron.py\"\n      cron: \n\n```\n\n\n---\n\n## FAQ\n\n### How to deploy site with IP and PORT (without SERVER_NAME) ?\n\nYou can deploy a site without a server name. \n\nThe server IP will be used instead of a server name\n\nYou need to set the `web.server_port` to the desired port. \n\nBeware the connection will not be behind NGINX nor use SSL. \n\nThis option is mainly for internal or IP based app.\n\n\n```\n# example sailor.yml\n\n...\n  process:\n    web: \n      ...,\n\n      #-- set server name to _\n      server_name: _\n      \n      #-- set server port\n      server_port: 8081\n\n```\n\n\n---\n\nTODO\n- Allow multiple server name on same app with their own ssl\n- Auto scaling, up to a max workers\n\n\n## CHANGELOG\n\n- 0.12.0\n  - Now installs on Ubuntu 22.04\n  - Supports Python 3.11 as `python3.11`\n  - Ubuntu 20.04 is still supported by using `install-2004.sh`\n\n- 0.11.1\n  - Update command `rm -f|--force` to force remove an application without the prompt. ie: `sailor rm -f $app_name`\n\n- 0.11.0\n  - Added possibility to deploy site without server_name but using IP and desired PORT\n  - Change commands to be more streamline\n    - ls \n    - start\n    - rm   \n    - x:update\n    - x:version\n  \n- 0.10.0\n  - Rebranding **Sailor**\n  - Added process option `enabled` to run/not-run a process. Especially if you don't want to run a process without removing the code.\n  - Fixed undefined value in setup_node_runtime\n  - fixed bindaddress bug\n\n- 0.5.0\n  - Added revision hash info and deploy time. \n  - Log deploy info \n  \n- 0.4.0\n  - added new proctype 'cron' To help execute cron. `cron` workers, which require a simplified `cron` expression preceding the command to be run (e.g. `cron: * * * * * python batch.py` to run a batch every minyte\n  ```\n  proces:\n    cron: \"* * * * * python cron.py\"\n  ```\n  - expand process list to allow process to have extended properties as dict/hash:\n  ```\n  process:\n    web:\n      cmd:\n      server_name:\n      workers:\n      \n    others:\n      cmd:\n      workers:\n  ```\n  - renamed command: 'app' -\u003e 'apps'\n  - fixed bug: log issues due to permission\n  - remove environment settings from command. Can now be added in the yml file\n  - `server_name` can now be added in `process.web.server_name` \n  - allow to system:update to be able to update from a different branch `system:update 1.2.0`\n\n\n- 0.3.1\n  - fixed letsencrypt issue\n\n- 0.2.0\n  - Rebranding Boxie to Sailor with Cardi B image, Okrrrrrr! (joke, joke)\n  - Remove Python 2 support.\n  - Recommend Ubuntu 20.04.\n  - Added separate install process for Ubuntu 2018.04\n  - Added custom index.html page\n  - Added aplication/json in nginx\n  - No longer supports self-signed SSL\n\n- 0.1.0\n  - Initial\n  - sailor.yml contains the application configuration\n  - 'app.run.web' is set for static/web/wsgi command. Static accepts one path\n  - added 'cli.upgrade' to upgrade to the latest version\n  - 'sailor.json' can now have scripts to run \n  - 'uwsgi' and 'nginx' are hidden, 'app.env' can contain basic key\n  - 'app.static_paths' is an array\n  - Fixed python virtualenv setup, if the repo was used for a different runtime\n  - Simplifying \"web\" worker. No need for static or wsgi.\n  - Python default to wsgi worker, to force to a standalone set env.wsgi: false\n  - reformat uwsgi file name '{app-name}___{kind}.{index}.ini' (3 underscores)\n  - static sites have their own directives\n  - combined static html \u0026 php\n  - Support languages: Python(2, 3), Node, Static HTML, PHP\n  - simplify command name\n  - added metrics\n  - Letsencrypt\n  - ssl default\n  - https default\n  - Multiple domain name deployment\n    ```\n---\n\n\n## Alternatives\n\n- [Dokku](https://github.com/dokku/dokku)\n- [Piku](https://github.com/piku/piku)\n- [Caprover](https://github.com/CapRover/CapRover)\n\nCredit: Sailor is a fork of **Piku** https://github.com/piku/piku. Great work and Thank you.\n\n---\n\nAuthor: Mardix\n\nLicense: MIT \n\nCopyright 2021, 2022 to Forever\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmardix%2Fsailor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmardix%2Fsailor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmardix%2Fsailor/lists"}