An alternative to the provisioning set out in “Test-Driven Development with Python, 2nd edition, by Harry J.W. Percival (O’Reilly). Copyright 2017 Harry Percival, 978-1-491-95870-4.”. Added provisioning via SSH only (including the GitHub repository), a non-root user for provisioning, and some hardening. Replace SITENAME below with your site's url, e.g., staging.mydomain.com. Replace USERNAME with the user added on the web server, e.g., slartibartfast.
- Python 3.6
- pip
- python3-venv
- nginx
- gunicorn
- git
Create new user on server:
- useradd USERNAME
- usermod -a -G sudo USERNAME
- mkdir /home/USERNAME
- mkdir /home/USERNAME/.ssh
- chmod 700 /home/USERNAME/.ssh
- passwd USERNAME
Create a new folder under /srv on server:
- mkdir /srv/SITENAME
- chown -R USERNAME /srv/SITENAME
- chgrp -R www-data /srv/SITENAME
- chmod -R 750 /srv/SITENAME
- chmod g+s /srv/SITENAME
-
vim /home/USERNAME/.ssh/authorized_keys
-
add the contents of the id_rsa.pub on the local machine:
cat /home/USERNAME/.ssh/id_rsa.pub
-
chmod 400 /home/USERNAME/.ssh/authorized_keys
-
chown USERNAME:USERNAME /home/USERNAME -R
-
vim /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
-
Addition if you have a fixed IP locally:
AllowUsers deploy@(your-ip) deploy@(another-ip-if-any)
-
Activate ufw (Ubuntu Firewall):
ufw allow 22
ufw allow 80
ufw allow 443
ufw enable
-
Alternative for port 22 (ssh) if you have a fixed IP locally:
ufw allow from {your-ip} to any port 22
-
Install fail2ban:
apt -y install fail2ban
Note: Feel free to go crazy on the hardening. This is just a minimum setup. A lynis audit is probably a good idea (for starters). Always good to keep practicality in mind, though...
- service ssh restart
- logout
- ssh USERNAME@server-ip
$ ssh-keygen -t rsa -b 4096 -C "[email protected]"
Before adding a new SSH key to the ssh-agent to manage your keys, you should have checked for existing SSH keys and generated a new SSH key.
-
Start the ssh-agent in the background.
$ eval "$(ssh-agent -s)"
Agent pid 59566
-
Add your SSH private key to the ssh-agent.
$ ssh-add ~/.ssh/id_rsa
-
Add the SSH key to your GitHub account.
OBS: Make sure the server complies with the requirements above before running the script. Install eventual missing software.
On the local machine:
/deploy_tools$ fab deploy:host=USERNAME@SITENAME
The following folder structure should be present on /srv/SITENAME after running the deployment:
srv
└── SITENAME
|--- .git
|--- deploy_tools
|--- functional_tests
|--- lists
|--- static
|--- superlists
|--- virtualenv
.env
.gitignore
README.md
db.sqlite3
manage.py
requirements.txt
-
cat ./deploy_tools/nginx.template.conf \
| sed "s/DOMAIN/SITENAME/g" \
| sudo tee /etc/nginx/sites-available/SITENAME
-
The result should be:
server {
listen 80;
server_name SITENAME;
location /static {
alias /srv/SITENAME/static;
}
location / {
proxy_set_header Host $host;
proxy_pass http://unix:/tmp/SITENAME.socket;
}
}
-
Add link in /etc/nginx/sites-enabled/SITENAME:
sudo ln -s /etc/nginx/sites-available/SITENAME /etc/nginx/sites-enabled/SITENAME
-
Remove 'default' from /etc/nginx/sites-enabled:
rm /etc/nginx/sites-enabled/default
-
Enable and start nginxi (reload if already started):
sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl start nginx (or reload)
-
cat ./deploy_tools/gunicorn-systemd.template.service \
| sed "s/DOMAIN/SITENAME/g" | sed "s/USERNAME/YOUR_USERNAME/g" \
| sudo tee /etc/systemd/system/gunicorn-SITENAME.service
- The result should be:
[Unit]
Description=Gunicorn server for SITENAME
[Service]
Restart=on-failure
User=YOUR_USERNAME
Group=www-data
WorkingDirectory=/srv/SITENAME
EnvironmentFile=/srv/SITENAME/.env
ExecStart=/srv/SITENAME/virtualenv/bin/gunicorn \
--bind unix:/tmp/SITENAME.socket \
superlists.wsgi:application
[Install]
WantedBy=multi-user.target
OBS: Note the User and Group definitions. Must be inluded in the template.
-
Enable and start gunicorn:
sudo systemctl enable gunicorn-SITENAME.service
sudo systemctl start gunicorn-SITENAME.service
H.J.W Percival's Test_driven Development In Python, Ch.10 https://www.obeythetestinggoat.com/book/chapter_making_deployment_production_ready.html
My First 5 Minutes With A Server https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers
GitHub: Generating a new SSH key on the server and adding it to the ssh-agent: https://help.github.com/en/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
Superuser-com on directory structures on web servers: https://superuser.com/questions/635289/what-is-the-recommended-directory-to-store-website-content
What permissions should my website files/folders have on a Linux webserver? https://serverfault.com/questions/357108/what-permissions-should-my-website-files-folders-have-on-a-linux-webserver#357109