Skip to main content

Installation

From purchase to the first SMS: buy, copy your key, install the gateway with one command, create the administrator, activate the license and pair a phone. Then day-to-day commands, troubleshooting and settings.

This page takes you from the purchase to a paired phone sending its first SMS. It assumes no prior knowledge of the product. Allow about a quarter of an hour, half of it spent downloading.

The installation fits in one command. A script installs Docker if it is missing, downloads the files of the latest version, checks that they have not been altered, writes the configuration, starts the gateway and installs an operations command, sms-gateway. You have nothing to compile and no server address to type in.

What you are installing

The gateway is one program, which listens on one port and keeps everything in one data folder (a Docker volume). It runs in a Docker container, on your machine.

You do not need Why
A database server The database is a single file inside the data folder, created at the first start
A separate web server for the dashboard The dashboard is built into the gateway and served on the same port as the API
Any third-party service The gateway contacts nobody except our license server and the webhooks you configure yourself. Your SMS, contacts and logs never leave your machine

Practical consequence: backing up the data folder backs up the whole installation, and moving it moves the gateway (see Backup and restore and Migrating to another server).

What you need

Item Detail
A machine Linux amd64 or arm64 (VPS, free Oracle Cloud instance, server or mini-PC on your premises, 64-bit Raspberry Pi), or a Windows or macOS computer with Docker Desktop
Administrator access root or sudo on Linux, PowerShell opened as administrator on Windows
Outbound internet access To download Docker and the gateway, and to activate the license. See Network access
For domain mode A domain name whose A (or AAAA) record points at the machine, and ports 80 and 443 reachable from the internet
For local network mode Phones connected to the same network as the machine
An Android phone Android 8 or later, with an active SIM and an SMS plan, kept on charge
Your license key Shown in your customer area after purchase

Nothing is compiled on your machine: the gateway is published ready to run for amd64 and arm64 processors, and Docker picks the right one. A small machine is enough: the gateway itself uses very little memory, and the smallest plan of most hosting providers is sufficient to start.

The path in five steps

Step 1: create your account and buy

Go to sms-gateway.araylab.com. The Buy button first asks you to sign in: enter your email address and you receive a sign-in link. There is no password to remember. You land in your customer area, empty for now.

Payment is handled by Gumroad, which also issues the invoice and handles VAT. In Madagascar, payment by Mobile Money (MVola, Orange Money, Airtel Money) is validated by hand: the license appears after that validation, not instantly.

Once the payment is confirmed, you receive an email announcing that the license is ready. For your security, that email does not contain the key: it sends you back to your customer area.

Step 2: copy your license key

In the customer area, the license shows its key, in the form XXXX-XXXX-XXXX-XXXX, with a button to copy it. The installation instructions and the download link for the Android app appear there too, as soon as the license is active.

You can come back at any time to display the key again, and regenerate it if it has leaked (see Regenerate the key).

Step 3: run the installation command

On the machine that will host the gateway, in a terminal.

Linux (VPS, Oracle Cloud, local server, Raspberry Pi):

curl -fsSL https://sms-gateway.araylab.com/install.sh | sudo bash

Without options, the script asks you two questions: whether it may install Docker if it is missing, and whether your phones will reach the gateway through a domain name or on the local network (see Choose the mode). To answer everything up front:

# With a domain name: automatic HTTPS (recommended)
curl -fsSL https://sms-gateway.araylab.com/install.sh | sudo bash -s -- --domain sms.example.com --yes

# On the local network, without a domain name
curl -fsSL https://sms-gateway.araylab.com/install.sh | sudo bash -s -- --lan --yes

macOS: the same command, with Docker Desktop installed and started beforehand. The installation goes into ~/sms-gateway, and the sms-gateway command is placed in that folder.

Windows (Docker Desktop required), in PowerShell opened as administrator:

irm https://sms-gateway.araylab.com/install.ps1 | iex

On Windows, the script asks no question about the mode: it installs in local network mode by default. To change that, set these variables in the same PowerShell window before running the command:

Variable Default Effect
$env:SMSGW_DOMAIN empty: local network mode Installs in domain mode, with automatic HTTPS on that name. On an existing installation, switches it to domain mode
$env:SMSGW_PORT 8080 Port of the gateway. Taken into account on the first installation only
$env:SMSGW_VERSION the latest published version Installs that precise version X.Y.Z
$env:SMSGW_DOMAIN = "sms.example.com"
irm https://sms-gateway.araylab.com/install.ps1 | iex

If Docker Desktop is missing, the Windows script offers to install it with winget, then stops and asks you to restart Windows, start Docker Desktop once, and run the command again. It installs into %ProgramData%\SmsGateway, opens port 8080 in the Windows firewall for private networks in local network mode, then opens the dashboard in your browser.

At the end, every script shows the dashboard address and the setup code used to create the administrator account (step 4). On Linux and macOS, sms-gateway url shows the address again and sms-gateway setup-code shows the code, as long as no account exists.

Prefer to read the script first? Piping a downloaded script into bash means trusting it. You can download it, read it, then run it:

curl -fsSL https://sms-gateway.araylab.com/install.sh -o install.sh
less install.sh
sudo bash install.sh --domain sms.example.com

The script, for its part, checks everything it downloads next against a published SHA-256 checksum: a file that does not match stops the installation before anything is installed.

What the script does, in order

  1. It checks that it runs as root on a Linux amd64 or arm64 machine (or on macOS).
  2. It installs Docker if it is missing, through Docker's official script, after asking you (or without asking with --yes).
  3. It finds the latest published version (or the one given with --version), downloads its files and checks their checksum.
  4. It asks for the mode if no option set it. In domain mode, it checks that the domain points at this machine and that ports 80 and 443 are free. A problem gives a warning and a question, not a hard stop: you can fix DNS afterwards.
  5. In local network mode, it installs avahi-daemon, which makes the name <machine-name>.local resolvable on your network.
  6. It writes the configuration to /opt/sms-gateway/.env, readable by root only. An existing configuration is kept: running the command again updates the gateway without erasing your settings.
  7. It downloads the gateway, starts it and waits until it answers (at most two minutes).
  8. It installs the sms-gateway command and shows the dashboard address, the setup code and the next steps.

The options (Linux and macOS)

Option Default Effect
--domain <name> none: the script asks Domain mode: HTTPS on that name, certificate obtained automatically. Ports 80 and 443 must be reachable. Sets the public address to https://<name>
--lan none: the script asks Local network mode: the gateway is served over HTTP on http://<machine-name>.local:<port>, to every device of the local network
--port <n> 8080 Port of the gateway on the machine. In local network mode, it is part of the address written into the QR codes
--dir <path> /opt/sms-gateway (~/sms-gateway on macOS) Installation folder, where the configuration lives. System folders are refused
--version <X.Y.Z> the latest published version Installs that precise version, for example to stay on a version you have tested
--yes off Asks no question: accepts the Docker installation and continues past warnings (DNS, busy ports)
--no-docker-install off Never installs Docker. If it is missing, the script stops and says so
--help - Shows the help and does nothing else

How the options interact:

  • Without --domain or --lan, the script asks. With --yes and no mode on a first installation, it stops: there is no default mode, because the wrong one gives phones that never connect.
  • On a new run over an existing installation, the mode and the port already recorded are kept. Giving --domain or --lan again switches the mode: the public address changes, and phones already paired must be paired again.
  • --port is only taken into account on the first installation. Afterwards, the port recorded in the configuration wins; change GATEWAY_PORT in the .env file instead (see Settings you can change).
  • --yes also answers yes to warnings. In domain mode, an installation with a wrong DNS or with ports 80/443 taken continues anyway: the gateway works, but HTTPS will not until you fix the cause.

Step 4: open the dashboard, create the administrator, paste the key

Open the address shown by the script. A fresh installation opens the Create the first account screen: Setup token, name, email address, password. The password must be at least 12 characters long. This first account is the superadministrator, and the screen that creates it closes for good as soon as an account exists.

The setup token is the setup code shown at the end of the script. It proves that the person creating the account has access to the machine: without it, the first stranger to find a freshly installed gateway on the internet could make themselves its administrator. If you no longer have it in front of you:

Where Command
Linux, macOS sms-gateway setup-code
Windows docker compose exec gateway /usr/local/bin/gateway setup-token, from %ProgramData%\SmsGateway

The code disappears as soon as the account is created: the commands above then answer that there is none left, and that is expected.

Creating the account does not sign you in: the screen confirms the creation, then sends you to the sign-in screen, where you type the email address and password you just chose.

Once signed in, an Activate this gateway window appears. Paste the key copied in step 2. Spaces, dashes and lowercase letters are accepted. There is nothing else to type: the gateway already knows how to reach our license server.

If our server does not answer at that moment, the window says Our server is not answering. Your key is recorded anyway and nothing is suspended: the gateway sends normally and retries the activation on its own. An outage on our side is never treated as an invalid license. Details in License.

Step 5: install the Android app and pair the phone

  1. Download the app from your customer area, on the phone itself or on a computer and then copied over. The app is not on the Play Store: the link is given only to license holders.
  2. Install it. Android asks you to allow installation from the source you used (browser or file manager). Allow it for this installation.
  3. In the dashboard, open Devices and click Pair a device. A QR code appears, with a fallback code for a phone whose camera does not work. It is valid for five minutes and can be used only once; Generate a new code gives you another.
  4. In the app, scan the QR code. The phone connects to the gateway and appears online in Devices, with its SIM cards.
  5. Send a test SMS from Quick send, then reply to it from another phone: the reply shows up in Conversations.

The app asks to be exempted from battery optimization and shows a permanent notification: that is what keeps it running in the background. Keep the phone on charge. Everything about phones (SIM, daily quota, keeping the phone awake) is in Devices.

If you type the address by hand instead of scanning, type it in full, with https:// or http:// (https://sms.example.com or http://server.local:8080). Without it, the app assumes an HTTPS connection, which fails on a local network installation.

Choose the mode: domain or local network

This is the only real choice in the installation, and it decides the address the phones dial. That address is written into every pairing QR code, then kept by the phone. A wrong address gives a QR code that scans perfectly and a phone that never reaches anything.

Question Domain mode (--domain) Local network mode (--lan)
For whom VPS, Oracle Cloud, any server reachable from the internet A server or computer on your premises, not exposed
Dashboard address https://sms.example.com http://<machine-name>.local:8080
Encryption HTTPS, certificate obtained and renewed automatically (Let's Encrypt) None: plain HTTP on your local network
Where phones can be Anywhere, 4G included Only on the same network as the machine
What the machine exposes Ports 80 and 443. The gateway itself stays private Port 8080, to every device on the local network
Prerequisites DNS pointing at the machine, ports 80 and 443 open The .local name must resolve on your network (the script installs what is needed on Linux)

Choose domain mode whenever you can: it has none of the caveats below.

What local network mode implies

  • The Android app accepts unencrypted connections only to a .local name. A plain IP address such as http://192.168.1.20:8080 is refused by the phone. That is why the installer uses http://<machine-name>.local:8080.
  • Check that the phone resolves that name before going further: open http://<machine-name>.local:8080/health in the phone's browser, connected to the same wifi. A {"status":"ok",...} response means pairing can work.
  • The dashboard session travels unencrypted on your network. The installer sets GATEWAY_INSECURE_COOKIES=true, otherwise browsers would refuse to keep you signed in over plain HTTP. Acceptable on a company network you control, not on a shared wifi.
  • The machine's name must not change, since it is written into the QR codes. Renaming it forces you to pair the phones again.
  • A guest wifi often isolates its devices: the phone sees the internet but not the machine. The /health test above reveals it. Put the phones on the internal network.

Everything specific to this path (fixed address, guest wifi, access from outside) is in Local server.

What domain mode implies

  • The DNS must point at the machine before the certificate can be obtained. The script warns you if it does not; the certificate is obtained automatically as soon as the DNS is right.
  • Ports 80 and 443 must be reachable from the internet, port 80 included: it is used to prove you own the domain. Open them in the machine's firewall and at your hosting provider, which often filters too.
  • Nothing else is exposed: a small web server (Caddy) handles HTTPS in front of the gateway, which itself only listens on the machine.
  • If a proxy such as Cloudflare sits in front of the domain, disable it while the certificate is obtained.

The sms-gateway command

Installed on Linux and macOS, it is run as root (or with sudo) from any folder.

Command What it does
sms-gateway status State of the gateway (and of the HTTPS server in domain mode)
sms-gateway logs Gateway logs, continuously. Ctrl+C to exit
sms-gateway url Shows the dashboard address
sms-gateway setup-code Shows the setup code, as long as no account exists
sms-gateway update [X.Y.Z] Moves to the latest version, or to the one given. Data and configuration are kept
sms-gateway restart Restarts the gateway, and applies a change made to the .env file
sms-gateway stop / start Stops or starts the gateway again without deleting anything
sms-gateway backup Writes an archive of the whole data folder to the current folder (see Backup)
sms-gateway uninstall Removes the gateway and the command. The data is kept
sms-gateway uninstall --purge Also deletes the data: everything is lost, messages, contacts, accounts and master key

Running the installation command again has the same effect as sms-gateway update.

On Windows, there is no sms-gateway command. Open PowerShell in %ProgramData%\SmsGateway and use Docker Compose directly:

To Command
See the state docker compose ps
Read the logs docker compose logs -f gateway
Restart docker compose restart gateway
Update Run the installation command again
Read the setup code docker compose exec gateway /usr/local/bin/gateway setup-token

Keep the computer on and Docker Desktop set to start with Windows: the gateway runs only while Docker Desktop is running.

Stopping or restarting loses nothing. While the gateway is down, phones keep outgoing and incoming messages in their own queue and hand them over when it comes back.

Regenerate the key

In the customer area, Regenerate key replaces your license key with a new one. Do it if the key has leaked (a support ticket, a screenshot, a former contractor), or to free the license before installing on another machine.

What changes What does not change
The old key is refused immediately for activating or renewing Your license: tier, version line, purchase date
No machine is attached to the license any more The gateway already installed keeps working and sending

The installed gateway does not stop. However, it can no longer renew its activation as long as it carries the old key: open License in the dashboard and enter the new key there. Two regenerations must be at least a minute apart.

Troubleshooting

Always start with sms-gateway status, then sms-gateway logs.

Symptom Likely cause and fix
Warning: ports 80 or 443 already in use Another web server (Apache, Nginx, a hosting panel) holds them. sudo ss -ltnp 'sport = :80' names it. Stop it, use another machine, or see VPS, existing web server. Continuing anyway leaves you without HTTPS
Startup fails because port 8080 is in use Set GATEWAY_PORT=8090 (or another free port) in /opt/sms-gateway/.env, then run the installation command again. In local network mode, add --lan so that the address in the QR codes takes the new port
Warning: the domain does not point at this machine Fix the A record at your registrar, wait for propagation (dig +short sms.example.com), then sms-gateway restart
The browser reports an invalid certificate The certificate has not been obtained yet: DNS not propagated, or port 80 closed at the host. sms-gateway logs caddy says why
The script says Docker is missing and stops You used --no-docker-install, or declined the installation. Install Docker with its compose plugin, or run again without that option
Windows: Docker Desktop does not start Docker Desktop needs virtualization enabled in the BIOS and WSL 2. Start it once by hand, then run the command again
The script waits, then says the gateway does not answer The last log lines are shown. See When the gateway refuses to start
The dashboard shows but signing in fails with no message You are using plain HTTP on an address other than the one the installer set up. Use the address shown by sms-gateway url
The setup token is refused It was mistyped, or it belongs to another installation. Read it again with sms-gateway setup-code and paste it as is
sms-gateway setup-code answers that there is no token An account already exists. Sign in with it. If nobody on your side created it, reinstall from scratch with sms-gateway uninstall --purge then the installation command
The phone does not pair: nothing happens after the scan The phone cannot reach the address in the QR code. Open https://sms.example.com/health (or http://<name>.local:8080/health) in the phone's browser. If it fails: guest wifi, phone on another network, .local name not resolved, ports closed
The phone refuses the address An http:// address that is not a .local name (an IP for example). Use the .local name, or switch to domain mode
The QR code is refused as expired A QR code lives five minutes and works once. Click Generate a new code
The QR code carries a wrong address Run the installation command again with the right --domain or --lan, then generate a new QR code. Codes already issued keep the old address
The license stays on Local token due for renewal The machine cannot reach our license server (outbound firewall, company proxy), or the key has been regenerated since. Sending is not affected. See License

Network access

The machine needs outbound HTTPS access to:

Address What for When
get.docker.com Installing Docker Only if Docker is missing
ghcr.io Downloading the gateway Installation and updates
bck2.araylab.com Downloading the installation files of a version Installation and updates
bck1.araylab.com License activation and periodic renewal While the gateway runs
api.ipify.org Comparing the machine's public address with the DNS Installation in domain mode

If bck1.araylab.com is blocked, nothing stops working, but the license screen will keep saying that our server does not answer.

Settings you can change

The installer writes the configuration to /opt/sms-gateway/.env (readable by root only; on Windows, %ProgramData%\SmsGateway\.env). For a standard installation, you have nothing to add. Everything you tune day to day (sending window, retries, time zone, notifications, routing rules...) is set in the dashboard, under Settings and the related screens, not here: see Settings. No setting of the dashboard has an equivalent variable, and no variable below can be changed from the dashboard.

After editing the .env file, apply the change with sms-gateway restart (on Windows: docker compose up -d in the installation folder). An update or a new run of the installer keeps the file; it only rewrites the version and, if you give --domain or --lan again, the mode lines.

In the .env file

These lines are written by the installer. You may edit them, knowing what each one drives.

Variable Default (written by the installer) Effect
SMSGW_MODE domain or lan, per your choice Remembers the mode, so that an update keeps it. Read by the installer only
GATEWAY_PUBLIC_URL https://<domain> or http://<machine>.local:<port> The address phones and browsers use. Written into every pairing QR code (https:// gives an encrypted phone link, http:// an unencrypted one) and used as the base of short links. Read at startup only
GATEWAY_DOMAIN your domain, or localhost in local mode The name the HTTPS certificate is requested for. Must be the host of GATEWAY_PUBLIC_URL
COMPOSE_PROFILES tls in domain mode, empty in local mode tls starts the HTTPS server (Caddy) in front of the gateway, on ports 80 and 443. Empty: no HTTPS server
GATEWAY_PORT 8080 (or --port) Port of the gateway on the machine. In local mode, it must match the port in GATEWAY_PUBLIC_URL
GATEWAY_BIND 127.0.0.1 in domain mode, 0.0.0.0 in local mode Which network interface the port listens on. 127.0.0.1: only the machine itself (the HTTPS server relays the rest). 0.0.0.0: every device of the network, in plain HTTP
GATEWAY_INSECURE_COOKIES false in domain mode, true in local mode true lets browsers keep you signed in over plain HTTP, at the price of a session that travels unencrypted. Changes nothing else
GATEWAY_VERSION the installed version The version that starts. Prefer sms-gateway update X.Y.Z, which also downloads the matching files
GATEWAY_IMAGE ghcr.io/andritianaa/sms-gateway Where the gateway is downloaded from. Do not change

The file also lists, commented out, the settings below (an update adds that list once to a .env written by an earlier version). Remove the # in front of a line to use it, then restart. The provided docker-compose.yml passes each of them to the gateway; left out or empty, the gateway uses its default. Because they live in .env and not in docker-compose.yml, an update keeps them.

Variable Default Effect
GATEWAY_LOG_LEVEL info Detail of the technical logs (sms-gateway logs and the technical view of Activity log): debug, info, warn or error. debug is verbose; no level ever writes the text of an SMS or a full phone number
GATEWAY_TRUSTED_PROXIES 172.31.254.2/32, the address of the built-in HTTPS server The reverse proxies allowed to report the visitor's real IP address, comma separated (addresses or CIDR blocks). The gateway uses that IP for sign-in lockouts and rate limits. Change it only if you put your own proxy in front: see VPS, existing web server
GATEWAY_LOG_RETENTION_DAYS 30 How many days an entry of the Activity log is kept before being deleted, from 1 to 3650. A longer retention makes the database grow; entries older than the new value are deleted by the next cleanup. See Activity log
GATEWAY_UPTIME_RETENTION_DAYS 90 How many days the connection history of the phones is kept for the Device uptime charts, from 90 to 3650. Below 90 days the 90-day chart would lose its oldest bars, hence the floor. Older history is deleted by the next hourly cleanup. See Devices
GATEWAY_ROUTING_MODE round_robin How messages are spread across SIM cards when no routing rule picks one: round_robin (in turn), quota (the SIM with the most room left in its daily quota) or carrier (the SIM of the recipient's carrier). See Routing
GATEWAY_CARRIER_PREFIXES empty Which number prefixes belong to which carrier, in the form Telma:+26134,+26138;Orange:+26132. The carrier names must be written as the SIM cards report them in Devices. Required in carrier mode, ignored otherwise. A number that matches no prefix is sent as in quota mode
GATEWAY_WEBHOOKS_ALLOW_PRIVATE_NETWORKS true Allows webhooks to addresses of your private network (a CRM on the same network, for example). false restricts them to public addresses. The machine's own addresses and cloud metadata addresses are refused in every case

Interactions to know:

  • The mode is four lines that go together: GATEWAY_PUBLIC_URL, GATEWAY_DOMAIN, COMPOSE_PROFILES and GATEWAY_BIND (plus GATEWAY_INSECURE_COOKIES). Changing one without the others gives, for example, a working HTTPS site and phones that do not pair. To change mode or domain, run the installer again with --domain or --lan: it rewrites them together.
  • Changing GATEWAY_PUBLIC_URL does not update phones already paired: they keep the address of their QR code. Pair them again after such a change.
  • GATEWAY_TRUSTED_PROXIES set too wide (for example 0.0.0.0/0) lets anyone pretend to be any IP address and get around the sign-in lockout. Left empty, the gateway sees every visitor as the proxy's address, and they all share the same limits.

Advanced settings

The gateway reads the two variables below too. They are not listed in the file the installer writes, because a customer installation rarely needs them.

Variable Default Effect
GATEWAY_SECRET_KEY generated at the first start and kept in secret.key The master key, 32 bytes in base64, if you prefer to keep it in a secret manager. Passed from .env by the provided docker-compose.yml. When set, it replaces secret.key. A different key from the one the installation started with makes paired phones, webhook secrets and the stored license key unreadable. See The master key
GATEWAY_ENV_FILE gateway.env next to the program A key=value file read before everything else. A variable already set in the environment always wins over the file. Missing file: ignored. Unreadable file: startup is refused. Not passed by the provided docker-compose.yml, whose .env plays that role

Leave these alone. They exist in the program, but a customer installation has no use for them:

Variable Default Why you should not set it
GATEWAY_DEV false Development mode. It removes the protection of the session cookie, accepts an unencrypted public address on any host, and lets the license server address and keys be replaced. The provided docker-compose.yml does not pass it, on purpose
GATEWAY_LICENSE_SERVER_URL our license server, built in Ignored unless GATEWAY_DEV=true (a warning says so in the logs). Must be https://
GATEWAY_LICENSE_PUBLIC_KEYS our public keys, built in Same rule: ignored unless GATEWAY_DEV=true
GATEWAY_ADDR :8080 Listening port inside the container. Change GATEWAY_PORT instead; changing this one breaks the health check
GATEWAY_DATA_DIR /data Data folder inside the container. Changing it moves the data out of the volume and changes the machine fingerprint

Backups have no variable: the automatic backup is set in the dashboard, under Settings > Backup and export. See Backup.

Two rules apply to every variable:

  • An empty value counts as absent: the default applies.
  • An invalid value stops the gateway at startup, with a message naming the variable, rather than running on a value you did not choose. See the next section.

When the gateway refuses to start

The message is in sms-gateway logs, on a line containing gateway stopped. The gateway restarts in a loop until the cause is fixed.

Cause What the log says
Unknown log level GATEWAY_LOG_LEVEL: "..." is not one of debug, info, warn, error
Activity log retention out of range GATEWAY_LOG_RETENTION_DAYS: "..." is not a number of days between 1 and 3650
Uptime history retention out of range GATEWAY_UPTIME_RETENTION_DAYS: "..." is not a number of days between 90 and 3650
Unknown routing mode GATEWAY_ROUTING_MODE: "..." is not one of round_robin, quota, carrier
carrier mode without a prefix table GATEWAY_ROUTING_MODE=carrier requires GATEWAY_CARRIER_PREFIXES
Malformed prefix table ... is not in the form Carrier:+prefix,+prefix
A yes/no setting with another value <VARIABLE>: "..." is not a boolean (use true or false)
Plain http:// public address that is not a .local name nor localhost GATEWAY_PUBLIC_URL: "..." is plain http on a non-local host; ...
Unreadable proxy address GATEWAY_TRUSTED_PROXIES: "..." is neither a CIDR block nor an address
Master key of the wrong size key is N bytes, expected 32 or key is not valid base64
Data folder unusable create data dir: ..., or an error opening the database
GATEWAY_ENV_FILE (or gateway.env) present but unreadable read <path>: ...
License server address in plain http:// GATEWAY_LICENSE_SERVER_URL: "..." must use https ...

Why a plain http:// address is refused: over HTTP, the dashboard session would travel unencrypted across the internet. Only a .local name (local network mode) or localhost is accepted without HTTPS.

Why carrier mode is refused without a table: it would route nothing by carrier, and you would believe you pay the on-network rate while paying the cross-network one.

A restore that fails (see Backup and restore) never prevents startup: the gateway starts on the database it has, and logs the error.

The master key

At the first start, the gateway creates a master key, secret.key, in its data folder. It protects the secrets of the paired phones, the webhook secrets and your license key stored in the database, and it identifies your machine to our license server (only a fingerprint derived from it is sent, never the key).

Losing it means pairing every phone again and entering the license key again. It lives next to the database, not inside it: a database export alone does not contain it, whereas the sms-gateway backup archive, which copies the whole data folder, does.

What the data folder contains

File Role
gateway.db (and -wal, -shm) The database: messages, contacts, conversations, settings, accounts
secret.key The master key
setup.token The setup code. Present only as long as no account exists
backups/ The backups made from the dashboard or the API
restore.pending.* Present only while a restore waits for the next restart
gateway.db.pre-restore-... The previous database, set aside after a restore, kept until you delete it

The container is locked down: it cannot write anywhere except this folder and a temporary space used for database exports. If you replace the provided docker-compose.yml with your own setup, keep the hostname: sms-gateway line (without it, every recreation of the container looks like a move to our license server) and the /tmp mount (without it, the database export fails).

Backup

The whole installation lives in the data folder. The simplest backup is:

sudo sms-gateway backup

Run from the folder where you want the archive, it stops the gateway for the few seconds of the copy (phones keep their messages meanwhile), writes sms-gateway-backup-<date>.tar.gz to the current folder, starts it again and waits until it answers. That archive contains the master key along with the database: store it as the most sensitive document of the installation, and not on the same machine.

The gateway also backs itself up automatically, without interrupting sending: every day at 03:00 in the platform time zone by default, seven copies kept, in the data folder. Change the time, the frequency and the number of copies, or turn it off, in Settings > Backup and export, which also lists and restores backups and exports your data as CSV or JSON. These copies stay on the machine: download one, or copy a sms-gateway backup archive, to keep a copy elsewhere.

Everything is detailed in Backup and restore.

The hosting guides

This page covers the installation itself. What is specific to each kind of machine has its own guide:

Where What it adds
Oracle Cloud Always Free Create the free instance and open the ports at both levels (Oracle and the instance)
VPS Prepare a rented server: DNS, firewall, existing web server, automatic startup
Local server The .local name, guest wifi, access from outside and availability

Next

You want to Go to
Manage your phones and SIM cards Devices
Send your first messages Sending
Send through the API API
Back up and restore Backup and restore
Move to another machine Migrating to another server
Know what protects your data Security

Search the documentation

Type a few words, then pick a page.