Setup HTTPS for Grin Wallet in Ubuntu and Apache

Today I’d like to share my own struggling experience to build my HTTPS Grin wallet with certified encrypted SSL certificate.


Assume that you are running a Grin node and Grin wallet listening on port 3415 in Ubuntu . And your HTTP wallet could receive Grin well from other wallets.
—This part is to help new users to run Grin node & wallet with least efforts—
Build a server for Grin node in Google Cloud

After you finish to register an account for Cloud service, please click on the link to get Cloud Shell:, click on ‘Launch Cloud Shell’.

Enter following command, or copy and paste (Control +Shift + V)

gcloud beta compute instances create grin-gg1 --zone=us-central1-b --machine-type=f1-micro --tags=grin-gg --image=ubuntu-1804-bionic-v20190530 --image-project=ubuntu-os-cloud --boot-disk-size=30GB --boot-disk-type=pd-standard --boot-disk-device-name=grin-disk1

You can switch 3 free zone locations:

  • 1 non-preemptible f1-micro VM instance per month in one of the following US regions:
    • Oregon: us-west1
    • Iowa: us-central1
    • South Carolina: us-east1

And you could change the OS image like Debian-9 which you want by command in cloud shell:

gcloud beta compute images list

You have just created a new Cloud Compute Instances named grin-gg1. Click on SSH button you will be able to open the terminal

Prepare the server for Grin node installation

Enter following command to update and install some tools, you will have to enter the ‘Y’ to confirm the steps

sudo apt-get update; sudo apt-get install git nano tmux pkg-config; sudo apt-get install clang cmake libncurses5-dev libncursesw5-dev zlib1g-dev libssl-dev

Install rust:

curl -sSf | sh; source $HOME/.cargo/env

Enter ‘1’ for default installation.

Clone grin and build a release version

git clone

cd grin

cargo build --release

The process could take an hour, so you could open second terminal to download Grin node and Grin wallet.

We will use wget to download those files in home directory

cd ~



tar -xvf grin-v3.1.0-linux-amd64.tar.gz

tar -xvf grin-wallet-v3.1.1-linux-amd64.tar.gz

We will use command tmux to open 3 sessions, one session is for Grin node running in background, second terminal is for Grin wallet to run in background to listening the port to receive Grin from other people. The third one is for doing some other commands.

tmux new -s grinrun
tmux new -s walletlisten
tmux new -s commands

In tmux GUI, you could use keyboard combination

  • Control+b-s to list sessions
  • Control+b-d to detach the session to normal bash GUI

tmux attach -t : to open the session you want

Start to run Grin node mainnet, in session named grinrun:

tmux new -s grinrun

cd ~

cd grin/


Start Grin Wallet to listen the port:

tmux new -s walletlisten

cd ~

cd grin-wallet/

./grin-wallet init ***#Enter your own password, remember to backup the seed (recovery phrase)!***

./grin-wallet -e listen

Change the configuration of Grin node and Grin wallet:

cd ~

cd .grin/main

Change Grin node configuration:

nano grin-server.toml

Change the entry to api_http_addr = “”

Change Grin Wallet configuration:

nano ~/grin-wallet/grin-wallet.toml

Change the entry to api_listen_interface = “”

After changing the configuration, restart the Grin node and Grin wallet listening in tmux sessions.

Allow Grin node and Grin wallet ports open to the internet

Go to Google Shell, copy following commands and paste (Contrl+Shift+V)

gcloud compute firewall-rules create main-wallet-port -direction=INGRESS -action=ALLOW -rules=tcp:3415 -target-tags=grin-gg

gcloud compute firewall-rules create main-api-port -direction=INGRESS -action=ALLOW -rules=tcp:3413 -target-tags=grin-gg

gcloud compute firewall-rules create main-p2p-port -direction=INGRESS -action=ALLOW -rules=tcp:3414 -target-tags=grin-gg

gcloud compute firewall-rules create floo-wallet-port -direction=INGRESS -action=ALLOW -rules=tcp:13415 -target-tags=grin-gg

Or you could manually create firewall rules by user graphic in webpage:

Check the current ports open in your server, use command below:

netstat -na|grep

The output will look like:

tcp 0 0* LISTEN
tcp 0 0* LISTEN
tcp 0 0* LISTEN
tcp 0 0* LISTEN

Now your ports are open and will be able to accessed by people around the world, and your wallet is accepting $GRIN like http://your_ip_address:3415

—End of Grin node & wallet installation part—

Technical Idea

I’m just a newbie, maybe I do not explain well but hope it helps someone new in this system administration. Expert! please comment/or correct if what I explained is wrong. Thanks in advance.

HTTP GRIN wallet:

  • Your GRIN wallet listening port 3415 <———> protocol HTTP <———> Internet wallets

HTTPs GRIN wallet:

  • Your GRIN wallet listening port 3415 <———> SSL Proxy by Apache <———> protocol HTTPs <———> Internet wallets

So for HTTPS, we have to install Reverse Proxy for SSL service, we could use self-signed certificate but not recommend. We could use certified Let’s Encrypt certificate for free.

Install Apache and Mods

sudo apt-get install apache2
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
sudo systemctl restart apache2

Whitelist the ports in your server

sudo ufw allow http
sudo ufw allow https

sudo ufw allow proto tcp from any to any port 3413,3414,3415

Allow ports in Amazon AWS

Identify the Security group associated with your node, edit the firewall rule in Amazon EC2

Install certified SSL with Let’s Encrypt

sudo wget -O /usr/sbin/certbot-auto
sudo chmod a+x /usr/sbin/certbot-auto

sudo certbot-auto --apache -d

Change the Apache Configuration

mkdir -p /etc/apache2/log/

sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
DocumentRoot /var/www/html
<Directory /var/www/html>
Options FollowSymLinks
AllowOverride All
Allow from all
LogLevel notice
ErrorLog /etc/apache2/log/grin-error.log
CustomLog /etc/apache2/log/grin-access.log combined
SSLEngine on
SSLStrictSNIVHostCheck On
SSLHonorCipherOrder on
SSLProtocol all -SSLv2 -SSLv3
<FilesMatch “\.(cgi|shtml|phtml|php)$”>
SSLOptions +StdEnvVars
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
BrowserMatch “MSIE [2-6]” nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
BrowserMatch “MSIE [17-9]” ssl-unclean-shutdown
SSLCertificateFile /etc/letsencrypt/live/
SSLCertificateKeyFile /etc/letsencrypt/live/
Include /etc/letsencrypt/options-ssl-apache.conf
SSLProxyEngine On
ProxyPreserveHost On
ProxyPass /
ProxyPassReverse /

Remember the “/” at the end of the port 3415, otherwise you will have following error in grin-error.log

[Fri Jun 10 17:32:48.244509 2019] [proxy:error] [pid 12212:tid 140660153763584] [client <source_ip_wallet>:56442] AH00898: DNS lookup failure for: returned by /v1/wallet/foreign/receive_tx

And grin-access.log will show return code HTTP 502

<source_ip_wallet> - - [10/Jun/2019:17:32:48 +0000] “POST /v1/wallet/foreign/receive_tx HTTP/1.1” 502 3954 “-” “grin-client”

Restart Apache Service:

sudo systemctl restart apache2

Auto review SSL Certificate:

crontab -e

0 2 * * * sudo /usr/sbin/certbot-auto -q renew

Testing your HTTPs Grin Wallet

Now your HTTPs wallet should be like: https :// (without port) because your HTTPs listening to port 443 by default, when GRIN sent to your wallet, it redirects to as your wallet listening.

Here is my test in my own server:

(In source wallet I will send 0.1 GRIN to
Sender will be charged default fee 0.008 GRIN

(In target wallet we should see the Shared Transaction Id as same as source wallet)
There will be no error message in grin-error.log, and grin-access.log will show return code HTTP 200 as below:

<source_ip_wallet> - - [11/Jun/2019:01:02:32 +0000] "POST /v1/wallet/foreign/receive_tx HTTP/1.1" **200** 10263 "-" "grin-client"

Test to withdraw GRIN from the crypto exchange

( DON’T FORGET: Only send 0.1 Grin to test your https wallet first, then send big amount)


Well done !
Make sure you mention to start your grin-wallet listener after setting everything up like in tmux or screen More comments later :slight_smile:

@tromp - It looks like this behavior isn’t exclusive to non-interactive txs. It appears people don’t trust interactive txs either :joy:

Very nice write-up! Thanks for sharing.


There is a space after the IP:port in your ProxyPass which should not be there.
Based on mod_proxy there should be no space. If someone would just copy&past it and change ServerName and SSLCertificateFile it would not work.

SSLProxyEngine On
ProxyPreserveHost On
ProxyPass /
ProxyPassReverse /

Use the pre-formatted tag here should solve the problem. :slight_smile:

1 Like

Thanks for your notice, at first I made my procedure with Word, some characters are automatically formatted. I corrected them as your recommended.

1 Like

thank you very much, I stole the bit on allowing TLS for the wallet and adapted it for my node, since I want to use my own grin 5.0.1 node with the Ironbelly iOS app over HTTPS.
Just wanted to check a couple a things with you:

  • I disallowed http from ufw and it seems to still work perfectly. I’d rather not open any unnecessary ports.
  • Can you confirm that by using apache2 in this way, there is no need to set the specific TLS settings inside grin-server.toml? the following bits
    #path of TLS certificate file, self-signed certificates are not supported
    #tls_certificate_file = ""
    #private key for the TLS certificate
    #tls_certificate_key = ""
  • this is generic, not strictly related to your guide. I see that Ironbelly asks for a grin node URL and a secret. It works with my HTTPS url and the secret found in .api_secret. Yet I see works without asking any secret. I would like to know how the Secret for the grin node plays a part in security, and when I should consider removing it. I might point some friends to this node in the future.

Thanks for the great work, it took me 5 minutes to setup TLS (even though I had to use snapd to install certbot since your way is deprecated on Debian 10 Buster, I followed this guide here)

1 Like