diff --git a/README.md b/README.md index 2687a45..f50596c 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ Tools you will need: * https://github.com/ava-labs/avalanchego/ * https://ipfs.io/#install * python3 (linux os will have this) +* python3-venv + +### Development I have provided a `Makefile` with some helpful stuff...make sure to install `make` to use it. @@ -16,7 +19,7 @@ I have provided a `Makefile` with some helpful stuff...make sure to install `mak make setup # install ipfs -make install-ipfs +sudo make install-ipfs # optional: install avalanchego make install-avax @@ -35,3 +38,69 @@ make dev # access at http://127.0.0.1:5000 ``` + +### Production + +You need a few more things: +* A VPS with a decent provider +* Nginx +* Certbot / Letsencrypt + +Below is a set of commands you can follow to get setup. I used Ubuntu 20.04 on Digital Ocean. Run the below commands as root or prepend `sudo`. + +``` +# install nginx +apt-get install nginx -y + +# install certbot +apt-get install certbot -y + +# point DNS records at your VPS w/ a domain you control + +# generate diffie hellman keys +openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 + +# setup nginx ssl config from this repo +cp conf/nginx-ssl.conf /etc/nginx/conf.d/ssl.conf + +# setup nginx site config from this repo +cp conf/nginx-site.conf /etc/nginx/sites-enabled/suchwowx.conf + +# generate TLS certificates +service nginx stop +certbot certonly --standalone -d --agree-tos -m -n +service nginx start + +# setup ipfs service account and storage location +useradd -m ipfs +mkdir -p /opt/ipfs +chown ipfs:ipfs /opt/ipfs + +# setup ipfs service daemon +cp conf/ipfs.service /etc/systemd/system/ipfs.service +systemctl daemon-reload +systemctl enable ipfs +systemctl start ipfs + +# setup suchwowx service account and storage location +useradd -m suchwowx +mkdir -p /opt/suchwowx + +# setup suchwowx application +git clone https://github.com/lalanza808/suchwowx /opt/suchwowx +cp /opt/suchwowx/env-example /opt/suchwowx/.env +vim /opt/suchwowx/.env +chown -R suchwowx:suchwowx /opt/suchwowx + +# setup suchwowx service daemon +cp conf/suchwowx.service /etc/systemd/system/suchwowx.service +systemctl daemon-reload +systemctl enable suchwowx +systemctl start suchwowx +``` + +At this point you should have Nginx web server running with TLS certificates generated with Letsencrypt/Certbot, Systemd services for IPFS daemon for serving files and Gunicorn for serving the Flask application. + +You'll obviously need to update some of your configuration files to match your domain/DNS, but it's fairly trivial. + +Reach out on Twitter or Discord if you need support. diff --git a/conf/ipfs.service b/conf/ipfs.service new file mode 100644 index 0000000..64979f0 --- /dev/null +++ b/conf/ipfs.service @@ -0,0 +1,19 @@ +[Unit] +Description=InterPlanetary File System (IPFS) daemon +Documentation=https://docs.ipfs.io/ +After=network.target + +[Service] +MemorySwapMax=0 +TimeoutStartSec=infinity +Type=notify +User=ipfs +Group=ipfs +StateDirectory=ipfs +Environment=IPFS_PATH=/opt/ipfs +ExecStart=/usr/local/bin/ipfs daemon --init --migrate +Restart=on-failure +KillSignal=SIGINT + +[Install] +WantedBy=default.target diff --git a/conf/nginx-site.conf b/conf/nginx-site.conf new file mode 100644 index 0000000..b59a79b --- /dev/null +++ b/conf/nginx-site.conf @@ -0,0 +1,44 @@ +# Redirect inbound http to https +server { + listen 80; + server_name suchwowx.xyz; + return 301 https://suchwowx.xyz$request_uri; +} + +# Load SSL configs and serve SSL site +server { + listen 443 ssl; + server_name suchwowx.xyz; + error_log /var/log/nginx/suchwowx.xyz-error.log warn; + access_log /var/log/nginx/suchwowx.xyz-access.log; + client_body_in_file_only clean; + client_body_buffer_size 32K; + # set max upload size + client_max_body_size 8M; + sendfile on; + send_timeout 600s; + + location / { + proxy_pass http://127.0.0.1:4000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Frame-Options "SAMEORIGIN"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect off; + } + + location /ipfs/ { + proxy_pass http://127.0.0.1:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Frame-Options "SAMEORIGIN"; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_redirect off; + } + + include conf.d/ssl.conf; + ssl_certificate /etc/letsencrypt/live/suchwowx.xyz/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/suchwowx.xyz/privkey.pem; +} diff --git a/conf/nginx-ssl.conf b/conf/nginx-ssl.conf new file mode 100644 index 0000000..390fb6b --- /dev/null +++ b/conf/nginx-ssl.conf @@ -0,0 +1,18 @@ +## SSL Certs are referenced in the actual Nginx config per-vhost +# Disable insecure SSL v2. Also disable SSLv3, as TLS 1.0 suffers a downgrade attack, allowing an attacker to force a connection to use SSLv3 and therefore disable forward secrecy. +# ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +# Strong ciphers for PFS +ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; +# Use server's preferred cipher, not the client's +# ssl_prefer_server_ciphers on; +ssl_session_cache shared:SSL:10m; +# Use ephemeral 4096 bit DH key for PFS +#ssl_dhparam /etc/ssl/certs/dhparam.pem; +# Use OCSP stapling +ssl_stapling on; +ssl_stapling_verify on; +resolver 8.8.8.8 1.1.1.1 valid=300s; +resolver_timeout 5s; +# Enable HTTP Strict Transport +add_header Strict-Transport-Security "max-age=0;"; +add_header X-Frame-Options "DENY"; diff --git a/conf/suchwowx.service b/conf/suchwowx.service new file mode 100644 index 0000000..ff58fcc --- /dev/null +++ b/conf/suchwowx.service @@ -0,0 +1,25 @@ +[Unit] +Description=SuchWowX meme service +Documentation=https://suchwowx.xyz +After=network.target + +[Service] +PermissionsStartOnly = true +PIDFile = /opt/suchwowx/data/gunicorn/suchwowx.pid +User = suchwowx +Group = suchwowx +WorkingDirectory = /opt/suchwowx +ExecStartPre = /bin/mkdir -p /opt/suchwowx/data/gunicorn +ExecStartPre = /bin/chown -R suchwowx:suchwowx /opt/suchwowx/data/gunicorn +Environment = FLASK_APP=suchwowx/app.py +Environment = FLASK_SECRETS=config.py +Environment = FLASK_ENV=production +Environment = FLASK_DEBUG=0 +ExecStart = /opt/suchwowx/.venv/bin/gunicorn --bind 127.0.0.1:4000 "suchwowx.app:app" --log-file /opt/suchwowx/data/gunicorn/gunicorn.log --pid /opt/suchwowx/data/gunicorn/suchwowx.pid --reload +ExecReload = /bin/kill -s HUP /opt/suchwowx/data/gunicorn/suchwowx.pid +ExecStop = /bin/kill -s TERM /opt/suchwowx/data/gunicorn/suchwowx.pid +ExecStopPost = /bin/rm -rf /opt/suchwowx/data/gunicorn/suchwowx.pid +PrivateTmp = true + +[Install] +WantedBy=default.target