An open source tool that lets you create a SaaS website from docker images in 10 minutes.

Overview

简体中文

Screenshots

for members ( who subscribe the plan )

index pricing subscription

for admin

settings members plans droplets

⚠️ This document was translated into English by deepl and can be improved by PR

An open source tool that lets you create SaaS websites from images in as little as 10 minutes.

Docker2SaaS is a tool that enables multi-tenancy through virtualization technology (calling cloud platform api ) with tenant management and subscription managment. It helps web application and service developers to quickly build websites for sale or subscription. All you need to do is make an image of your application and then set up and configure a Docker2SaaS site to start selling your application as a service.

When a user's subscription is successful, it automatically creates a VPS from the image as configured; when the user cancels the subscription and it expires, it automatically deletes the VPS. Users can login to the site and see their subscription, host IP information, and other details. Additional extensions can be added.

The diagram below shows how Docker2SaaS interacts between: End Users
Payment provider: Stripe Cloud service provider: DigitalOcean.

Target Users of Docker2SaaS

Docker2SaaS is aimed at developers of cloud applications, providing them with a solution to quickly monetize their applications.

Let's say you develop a nice little web app and open source it to Github. Developers easily build it and use it on their own, but as the app becomes more popular, so do non-technical users. But even if they have already made a docker file, it is still difficult for them.

At this point you may want to provide a cloud hosting version. On the one hand, you can solve the details of the build for non-technical users, and on the other hand, hosting can bring some profit, so you can get a financial return.

However, this can create an additional amount of development, and it doesn't seem wise to spend weeks on development before you know if cloud hosting will be popular.

Fortunately, the open source Docker2SaaS solves this problem, and it only takes ten minutes to configure and you can get a simple and usable cloud hosting sales site. It's immediately ready for early sales, and you can modify the source code to add more business-related features as user demand increases.

Of course, it can also be used to build a third-party sales site under the license of a cloud application developer. But overall, Docker2SaaS is designed for developers and does not take into account the experience of non-technical users, so if you don't have a technical background, it's better to use a Docker2SaaS site that someone else has built rather than building it yourself.

PS: Docker2SaaS is built on Laravel, and while no knowledge is required for a simple deployment, if you want to customize and add features, then you need to have a little Laravel development knowledge.

Docker2Saas is licensed under the GPLv2 with an additional non-compete clause.

Docker2SaaS Guide

Steps

Digital Ocean configuration

Create a Digital Ocean image

We assume that you have already made a docker image of your application and can start it with the docker-compose command. Let's use Ghost as an example to explain.

First we will create a droplet( Digital Ocean calls its VPS droplet ) on Digital Ocean and select docker on ubuntu under marketplace.

Then we log in to the newly created instance via SSH. Create our docker-compose.yaml file in the root directory (or somewhere else). Here we use the yaml provided by bitnami.

version: '2'
services:
  mariadb:
    restart: always
    image: 'docker.io/bitnami/mariadb:10.3-debian-10'
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
      - MARIADB_USER=bn_ghost
      - MARIADB_DATABASE=bitnami_ghost
    volumes:
      - 'mariadb_data:/bitnami'
  ghost:
    restart: always
    image: 'docker.io/bitnami/ghost:3-debian-10'
    environment:
      - MARIADB_HOST=mariadb
      - MARIADB_PORT_NUMBER=3306
      - GHOST_DATABASE_USER=bn_ghost
      - GHOST_DATABASE_NAME=bitnami_ghost
      - ALLOW_EMPTY_PASSWORD=yes
      - GHOST_HOST=localhost
      - [email protected]
      - GHOST_PASSWORD=admin
    ports:
      - '80:2368'
    volumes:
      - 'ghost_data:/bitnami'
    depends_on:
      - mariadb
volumes:
  mariadb_data:
    driver: local
  ghost_data:
    driver: local

Note that we have added restart: always to ensure that docker is started automatically when the image is started.

Once the file is created, go to droplet management and create a snapshot.

When you are done creating the snapshot, you can delete the droplet instance.

Go to the images page and look up the data-id of the snapshot in the source code corresponding to the snapshot entry you just created, this value (78661121 in the image) is the id of the snapshot. Record it, and we'll use it later. (We'll call this A1)

Creating a Digital Ocean Token

Next we will create a token so that we can manage droplet through the API. At the bottom of the left menu, select API.

In the Tokens/Keys tab, generate a new token with the read && write permissions selected. Once generated, record it and you will need it later. (We'll call it A2)

Stripe Configuration

The following are all described in Test mode.

Create a subscription

Go to the Stripe dashboard and create a product.

Note that in the Pricing section, select Recurring so that it will automatically renew. Fill in the rest of the fields as you wish.

After creating the product, go to the product details page, and you can see the API ID in the Pricing section, and record it. (We'll write it down as B1)

You can create as many prices as you need, remember to record the price ids.

Get API key

In order to interact with the Stripe platform through the API, we also need the API key. click the Developer menu on the left, select API Keys, and record the publishable key and secret key on the right. (Note B2, B3)

Since then, the preparation is done.

Configuring Docker2SaaS

Site initialization

Download/clone the docker2saas source code to the environment where you want to run the sales site. This environment needs to be configured with PHP7.4+ and MySQL.

git clone https://gitlab.com/easychen/docker-2-saas.git --depth=1 docker2saas

Initialization of dependency packages:

cd docker2saas 
composer install

Rename .env.example to .env and run the command to generate APP_KEY

php artisan key:generate

Fill in other relevant information.

  1. APP_DEBUG : should be set to false after debugging is completed
  2. APP_URL : Website URL
  3. APP_LOGO_URL and APP_ICON_URL: Home page big picture and top menu icon
  4. DB_*: database related configuration
  5. STRIPE_KEY: the B2 in the previous article
  6. STRIPE_SECRET: B3 in the previous section

After creating the database docker2saas in MySQL, then run the command to initialize the database.

php artisan migrate

Start the development environment

php artisan serve --host=0.0.0.0 --port=8001

You can see the website by accessing port 8001 of the machine ip. Click register to register users and login automatically, the first registered user will become administrator automatically.

The administrator's logic can be modified in app/Providers/AuthServiceProvider.php.

Gate::define('saas-admin', function (User $user) {
            return $user->id == 1;         
});

Configure the site

Click on the settings tab to configure the basic information for the site, where DigitalOcean token is A2 from above.

The DigitalOcean sshkey is the public key you want to use to manage all droplets. if you don't have one ready, you can create one by running the following command.

ssh-keygen -t rsa  -f <name>

During the run, if you don't want to set the passphrase, you can just press enter twice to set it to empty.

ssh-keygen -t rsa  -f this
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 

When this is done, .pub will be generated in the command directory, and its contents will be the sshkey we want to fill in the form.

Create a subscription plan

Click Add a plan on the Plans page to add a subscription plan.

  1. Name: the name of the plan visible to the user, e.g. pro
  2. Stripe Price ID: B1 in the previous article
  3. DigitalOcean Droplet Region: the region where the created cloud host is located
  4. DigitalOcean Droplet Size: the model of the created cloud host

The region and size values can be obtained from the Digital Ocean official website on the Create Droplet page. After you have selected the desired region and model, the default name of the generated cloud host is the size in the selected section as shown below, followed by the sgp1 section which is the region.

  1. DigitalOcean Droplet Image: A1 in the previous section
  2. DigitalOcean Droplet User Data: Custom information that can be accessed in the cloud host, which can be used to pass information about the purchased user, such as email, etc. The details of what is used will be explained later. You can leave it blank for now.

After saving, you will get a Link in the list screen, which you can click to enter the subscription process of the plan. (This link is called C1)

Click on the Pricing page to see a preset plan display page.

This page can be customized by editing resources/views/pricing.blade.php. This page uses the blade syntax, but is composed almost entirely of HTML, so it is not too difficult to modify.

In addition to modifying the style and service offerings, you should pay special attention to the Subscribe button below, which should link to the corresponding plan, as in C1 above.

Similarly, edit resources/views/dashboard.blade.php to modify the dashboard page that users see after registering, where you can add instructions and help related to the cloud service.

Other configuration items

Timed tasks

Docker2Saas monitors expired users daily and removes their cloud hosts. To be able to execute it regularly, you need to add the commands for this item to the system crontab:. macos/deepLFree.translatedWithDeepL.text

* * * * * php </path/to/docker2saas>/artisan schedule:run

Webhook

Since users can modify their subscriptions on the Stripe website, subscription modifications and payment confirmations in Docker2Saas are done via webhook.

The webhook requires an externally accessible URL, which is recommended to be configured after going live. If you are debugging locally, you can use ngrok for intranet penetration.

Suppose the URL of Docker2Saas website is http://D.com, then the webhook endpoint URL is http://D.com/stripe/webhook.

Select the following events at events to send.

  1. invoice.created
  2. invoice.paid
  3. invoice.payment_action_required
  4. customer.subscription.created
  5. customer.subscription.updated
  6. customer.subscription.deleted
  7. customer.created
  8. customer.updated
  9. customer.deleted

Note that the customer.subscription.updated is a subscription change, which is not handled by default as it involves the specific hierarchy logic behind the cloud application. You can implement it yourself in app/Http/Controllers/WebhookController.php.

At this point, the site is ready for normal transactions. Note that here we are using develop server for debugging, and in order to support more users, you should switch to dedicated server software such as Nginx. For details, please refer here.

Initializing a mirror using user data

In a Ghost mirror, we need to know the IP address or domain name of the current droplet to configure the connection path; we also need to know the email address of the user to create a default account for them.

So we need a way to get user information in the mirror. When creating the plan above, we have a user data option (noted as F1) that is used to do just that.

This is a mechanism provided by Digital Ocean, in all droplets, just visit http:// 169.254.169.254/metadata/v1/user-data to get the information passed in during creation.

You can view it in droplet with the curl command.

curl http://169.254.169.254/metadata/v1/user-data

But there is a problem that each user has a different email address. So we need to have variables to support when we fill in the F1 place. Here Docker2Saas provides $user variables via the blade syntax, so you can insert the user id via {{$user->id}} and the email via {{$user->email}}.

uid={{$user->id}}

You can even put the docker-compose.yml template directly at F1.

Of course, in the droplet image, you also need to configure the appropriate startup script to get this data and configure it.

In addition, through curl http://169.254.169.254/metadata/v1 you can also get droplet related information, such as ip, domain name, etc. For the specific format, please refer to the related documentation.

License

This project uses the GPLv2 License with conditions.

Both individuals and commercial companies can use Docker2SaaS to build their own cloud application sales sites under the GPLv2 license.

However, selling Docker2SaaS itself as a Cloud Hosting service (e.g., making Docker2SaaS an image and selling it as a cloud service through Docker2SaaS or other platforms) is prohibited.

You might also like...
This simple code lets you to get how many % of this year had passed

Year-Percent-PHP This simple code lets you to get how many % of this year had passed Code is part of Telegram bot and was made for Telegram channel Ye

A PocketMine-MP plugin that lets you teleport among offline players

OfflinePlayerTP A PocketMine-MP plugin that lets you teleport among offline players. Commands Command Description /otp player Teleport to (offline)

This Pocketmine-MP plugin lets you implement the ultimate birthday wishing system on your server.

BirthdaysPE This Pocketmine-MP plugin will let you wish player(s) a happy birthday and notify others to wish them too. Commands /birthday set/reset

LendCash is a cash lending service that lets you take loans against your stocks portfolio value and pay back on a prorated basis.

LendCash is a cash lending service that lets you take loans against your stocks portfolio value and pay back on a prorated basis.

Laravel Larex lets you translate your whole Laravel application with a single CSV file.
Laravel Larex lets you translate your whole Laravel application with a single CSV file.

Laravel Larex Laravel Larex lets you translate your whole Laravel application with a single CSV file. You can import translation entries from lang fol

 A complete solution for group projects in organizations that lets you track your work in any scenario. Working in a team is a cumbersome task, ease it using our project management system.
A complete solution for group projects in organizations that lets you track your work in any scenario. Working in a team is a cumbersome task, ease it using our project management system.

SE-Project-Group24 What is Evolo? Evolo is Dashboard based Project Management System. A complete solution for group projects in organizations that let

 Enterprise Modular SAAS Framework, Design from the growndup to grow vertically.
Enterprise Modular SAAS Framework, Design from the growndup to grow vertically.

Kwerio Enterprise Modular SAAS Framework, Design from the growndup to grow vertically. Explore the docs » View Demo · Report Bug · Request Feature Tab

Laravel Plans is a package for SaaS apps that need management over plans, features, subscriptions, events for plans or limited, countable features.

Laravel Plans Laravel Plans is a package for SaaS apps that need management over plans, features, subscriptions, events for plans or limited, countabl

Comments
  • Bump follow-redirects from 1.13.2 to 1.14.7

    Bump follow-redirects from 1.13.2 to 1.14.7

    Bumps follow-redirects from 1.13.2 to 1.14.7.

    Commits
    • 2ede36d Release version 1.14.7 of the npm package.
    • 8b347cb Drop Cookie header across domains.
    • 6f5029a Release version 1.14.6 of the npm package.
    • af706be Ignore null headers.
    • d01ab7a Release version 1.14.5 of the npm package.
    • 40052ea Make compatible with Node 17.
    • 86f7572 Fix: clear internal timer on request abort to avoid leakage
    • 2e1eaf0 Keep Authorization header on subdomain redirects.
    • 2ad9e82 Carry over Host header on relative redirects (#172)
    • 77e2a58 Release version 1.14.4 of the npm package.
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies javascript 
    opened by dependabot[bot] 0
  • Bump laravel/framework from 8.27.0 to 8.40.0

    Bump laravel/framework from 8.27.0 to 8.40.0

    Bumps laravel/framework from 8.27.0 to 8.40.0.

    Release notes

    Sourced from laravel/framework's releases.

    v8.40.0

    Added

    • Added Illuminate\Database\Eloquent\Builder::withOnly() (#37144)
    • Added Illuminate\Bus\PendingBatch::add() (#37151)

    Fixed

    • Fixed Cache store with a name other than 'dynamodb' (#37145)

    Changed

    • Added has environment variable to startProcess method in ServeCommand (#37142)
    • Some cast to int in Illuminate\Database\Query\Grammars\SqlServerGrammar (09bf145)

    v8.39.0

    Added

    • Added Illuminate\Collections\Collection::sole() method (#37034)
    • Support url for php artisan db command (#37064)
    • Added Illuminate\Foundation\Bus\DispatchesJobs::dispatchSync() (#37063)
    • Added Illuminate\Cookie\CookieJar::expire() (#37072, fa3a14f)
    • Added Illuminate\Database\DatabaseManager::setApplication() (#37068)
    • Added Illuminate\Support\Stringable::whenNotEmpty() (#37080)
    • Added Illuminate\Auth\SessionGuard::attemptWhen() (#37090, e3fcd97)
    • Added password validation rule (#36960)

    Fixed

    • Fixed JsonResponse::fromJasonString() double encoding string (#37076)
    • Fallback to primary key if owner key doesnt exist on model at all in MorphTo relation (a011109)
    • Fixes for PHP 8.1 (#37087, #37101)
    • Do not execute beforeSending callbacks twice in HTTP client (#37116)
    • Fixed nullable values for required_if (#37128, 86fd558)

    Changed

    • Schedule list timezone command (#37117)

    v8.38.0

    Added

    • Added a wordCount() string helper (#36990)
    • Allow anonymous and class based migration coexisting (#37006)
    • Added Illuminate\Broadcasting\Broadcasters\PusherBroadcaster::setPusher() (#37033)

    Fixed

    • Fixed required_if boolean validation (#36969)
    • Correctly merge object payload data in Illuminate\Queue\Queue::createObjectPayload() (#36998)
    • Allow the use of temporary views for Blade testing on Windows machines (#37044)
    • Fixed Http::withBody() not being sent (#37057)

    v8.37.0

    Added

    ... (truncated)

    Changelog

    Sourced from laravel/framework's changelog.

    v8.40.0 (2021-04-28)

    Added

    • Added Illuminate\Database\Eloquent\Builder::withOnly() (#37144)
    • Added Illuminate\Bus\PendingBatch::add() (#37151)

    Fixed

    • Fixed Cache store with a name other than 'dynamodb' (#37145)

    Changed

    • Added has environment variable to startProcess method in ServeCommand (#37142)
    • Some cast to int in Illuminate\Database\Query\Grammars\SqlServerGrammar (09bf145)

    v8.39.0 (2021-04-27)

    Added

    • Added Illuminate\Collections\Collection::sole() method (#37034)
    • Support url for php artisan db command (#37064)
    • Added Illuminate\Foundation\Bus\DispatchesJobs::dispatchSync() (#37063)
    • Added Illuminate\Cookie\CookieJar::expire() (#37072, fa3a14f)
    • Added Illuminate\Database\DatabaseManager::setApplication() (#37068)
    • Added Illuminate\Support\Stringable::whenNotEmpty() (#37080)
    • Added Illuminate\Auth\SessionGuard::attemptWhen() (#37090, e3fcd97)
    • Added password validation rule (#36960)

    Fixed

    • Fixed JsonResponse::fromJsonString() double encoding string (#37076)
    • Fallback to primary key if owner key doesnt exist on model at all in MorphTo relation (a011109)
    • Fixes for PHP 8.1 (#37087, #37101)
    • Do not execute beforeSending callbacks twice in HTTP client (#37116)
    • Fixed nullable values for required_if (#37128, 86fd558)

    Changed

    • Schedule list timezone command (#37117)

    v8.38.0 (2021-04-20)

    Added

    • Added a wordCount() string helper (#36990)
    • Allow anonymous and class based migration coexisting (#37006)
    • Added Illuminate\Broadcasting\Broadcasters\PusherBroadcaster::setPusher() (#37033)

    Fixed

    • Fixed required_if boolean validation (#36969)
    • Correctly merge object payload data in Illuminate\Queue\Queue::createObjectPayload() (#36998)
    • Allow the use of temporary views for Blade testing on Windows machines (#37044)
    • Fixed Http::withBody() not being sent (#37057)

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • kubernetes 2 saas ?

    kubernetes 2 saas ?

    nice tool, would it make sens to consider kube 2 saas front that does this :

    • it has some dummy example single-container helm chart template
    • it takes this template, docker image name from the user and optionally a subdomain name
    • it launches the container (+- some extra options) and gives user a random subdomain or the one he wants

    I know this require some test kube setup, but this is the easy part ;)

    opened by sokoow 1
Owner
Easy
Easy
🐋 This project aims to broaden knowledge of system administration by using Docker: virtualizing several Docker images, creating them in a new personal virtual machine.

?? This project aims to broaden knowledge of system administration by using Docker: virtualizing several Docker images, creating them in a new personal virtual machine.

Anton Kliek 1 Jan 26, 2022
Agora Open source SaaS billing system for software companies

About Agora Invocing Billing and subscription management for SaaS & other software businesses. Handling signups, provisioning, billing and support Ago

Ladybird Web Solution 158 Dec 17, 2022
A web app for the resolution of a mobile game in wich you have 4 images and a list of letters, then a few boxes to fill with the word connecting the four images.

4images_1mot_solutions A web app for the resolution of a mobile game in wich you have 4 images and a list of letters, then a few boxes to fill with th

FOTSO Claude 3 Jan 13, 2022
A complete stack for running Symfony 5 into Docker containers using docker-compose tool and with Certbot for the HTTPS certificate.

?? Docker + PHP 7.4 + MySQL8.0 + Nginx + Certbot(HTTPS) + Symfony 5 Boilerplate ?? Edited from https://github.com/ger86/symfony-docker version -> http

null 6 Nov 9, 2022
Create eye-catching Open Graph images for each (or some) site pages

Open Graph Image Generator for Laravel Create Open Graph images (og:image, twitter:image, vk:image) for each (or some) site pages. Use page title to c

Pavel Bychko 4 Nov 11, 2022
Docker images for Cyber_Security hakathon 2021.

This repository contains a set of vulnerable Docker images for attacking the container environment compiled for Cyber_Security hackathon 2021. Require

null 1 Dec 1, 2022
Official OpenMage LTS codebase | Migrate easily from Magento Community Edition in minutes

Official OpenMage LTS codebase | Migrate easily from Magento Community Edition in minutes! Download the source code for free or contribute to OpenMage LTS | Security vulnerability patches, bug fixes, performance improvements and more.

OpenMage 782 Jan 3, 2023
Greyhole uses Samba to create a storage pool of all your available hard drives, and allows you to create redundant copies of the files you store.

Greyhole Greyhole is an application that uses Samba to create a storage pool of all your available hard drives (whatever their size, however they're c

Guillaume Boudreau 245 Dec 18, 2022
Docker-magento2 - 🐳 Docker containers with all required Magento 2 dependencies installed available as FPM through Nginx and CLI

Magento 2 Docker A collection of Docker images for running Magento 2 through nginx and on the command line. Quick Start cp composer.env.sample compose

Meanbee 454 Dec 27, 2022
Docker-magento - Docker image for Magento 1.6 to 1.9

Docker image for Magento 1.x This repo creates a Docker image for Magento 1.x. Please note The primary goal of this repo is to create Docker images fo

Fu Cheng 144 Nov 18, 2022